Skip to content
Open
11 changes: 11 additions & 0 deletions sdk/mx.sdk/mx_sdk_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -5613,6 +5613,12 @@ def version(self):
def applicationDist(self):
return mx.library("PETCLINIC_" + self.version(), True).get_path(True)

def extra_image_build_argument(self, benchmark, args):
additional_configuration = os.path.join(getattr(self, '.mxsuite').mxDir, "petclinic-config")
return [
f"-H:ConfigurationFileDirectories={additional_configuration}",
] + super(BasePetClinicBenchmarkSuite, self).extra_image_build_argument(benchmark, args)


class PetClinicWrkBenchmarkSuite(BasePetClinicBenchmarkSuite, BaseWrkBenchmarkSuite):
"""PetClinic benchmark suite that measures throughput using Wrk."""
Expand Down Expand Up @@ -5714,8 +5720,13 @@ def extra_image_build_argument(self, benchmark, args):
"org.apache.xmlbeans.metadata.system.sXMLLANG.TypeSystemHolder",
"org.apache.xmlbeans.metadata.system.sXMLSCHEMA.TypeSystemHolder"
]
tika_run_time_init = [
# Prevents build-time ininitialization of sun.awt.datatransfer.DesktopDatatransferServiceImpl through DefaultDesktopDatatransferService.INSTANCE
"sun.datatransfer.DataFlavorUtil$DefaultDesktopDatatransferService"
]
return [
f"--initialize-at-build-time={','.join(tika_build_time_init)}",
f"--initialize-at-run-time={','.join(tika_run_time_init)}",
] + super(BaseTikaBenchmarkSuite, self).extra_image_build_argument(benchmark, args)


Expand Down
37 changes: 37 additions & 0 deletions sdk/mx.sdk/petclinic-config/reachability-metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"reflection": [
{
"type": "org.apache.coyote.AbstractProtocol",
"methods": [
{
"name": "setProperty",
"parameterTypes": [
"java.lang.String",
"java.lang.String"
]
},
{
"name": "getAddress",
"parameterTypes": []
}
]
},
{
"type": "org.apache.coyote.http11.AbstractHttp11Protocol",
"methods": [
{
"name": "isSSLEnabled",
"parameterTypes": []
}
]
},
{
"type": "com.zaxxer.hikari.HikariDataSource",
"fields": [
{
"name": "pool"
}
]
}
]
}
1 change: 1 addition & 0 deletions sdk/src/org.graalvm.nativeimage/snapshot.sigtest
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ meth public java.lang.Class<?> getDeclaringClass()
meth public java.lang.Class<?> getElementType()
meth public java.lang.Class<?>[] getParameterTypes()
meth public java.lang.String getElementName()
meth public static boolean isInvocable(java.lang.reflect.Executable)
supr java.lang.LinkageError
hfds declaringClass,elementName,elementType,parameterTypes,serialVersionUID

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@

import java.io.Serial;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.graalvm.nativeimage.impl.ReflectionIntrospector;

/**
* This exception is thrown when a reflective query (such as
* {@link Class#getMethod(String, Class[])}) tries to access an element that was not <a href=
Expand Down Expand Up @@ -152,4 +155,14 @@ public String getElementName() {
public Class<?>[] getParameterTypes() {
return parameterTypes;
}

/**
* @return Whether the executable can be invoked without throwing a
* {@link MissingReflectionRegistrationError}.
*
* @since 25.1
*/
public static boolean isInvocable(Executable executable) {
return !ImageSingletons.contains(ReflectionIntrospector.class) || ImageSingletons.lookup(ReflectionIntrospector.class).isInvocable(executable);
}
}
Original file line number Diff line number Diff line change
@@ -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.
*
* The Universal Permissive License (UPL), Version 1.0
*
* Subject to the condition set forth below, permission is hereby granted to any
* person obtaining a copy of this software, associated documentation and/or
* data (collectively the "Software"), free of charge and under any and all
* copyright rights in the Software, and any and all patent rights owned or
* freely licensable by each licensor hereunder covering either (i) the
* unmodified Software as contributed to or provided by such licensor, or (ii)
* the Larger Works (as defined below), to deal in both
*
* (a) the Software, and
*
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
* one is included with the Software each a "Larger Work" to which the Software
* is contributed by such licensors),
*
* without restriction, including without limitation the rights to copy, create
* derivative works of, display, perform, and distribute the Software and make,
* use, sell, offer for sale, import, export, have made, and have sold the
* Software and the Larger Work(s), and to sublicense the foregoing rights on
* either these or other terms.
*
* This license is subject to the following condition:
*
* The above copyright notice and either this complete permission notice or at a
* minimum a reference to the UPL must be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.graalvm.nativeimage.impl;

import java.lang.reflect.Executable;

/**
* Provides an interface to query whether an executable has invocation capabilities, or was only
* registered for reflective queries.
*/
public interface ReflectionIntrospector {
boolean isInvocable(Executable executable);
}
1 change: 1 addition & 0 deletions substratevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This changelog summarizes major changes to GraalVM Native Image.
* (GR-68984) Ship the `reachability-metadata-schema.json` together with GraalVM at `<graalvm-home>/lib/svm/schemas/reachability-metadata-schema.json`.
* (GR-68984) Improve the schema to capture detailed constraints about each element in the `reachability-metadata-schema.json`.
* (GR-70046) Remove all support for running image builder on classpath.
* (GR-69577) Retire `--future-defaults=complete-reflection-types`. All reflective operations on types registered for reflection will now return complete results.

## GraalVM 25
* (GR-52276) (GR-61959) Add support for Arena.ofShared().
Expand Down
9 changes: 7 additions & 2 deletions substratevm/mx.substratevm/mx_substratevm_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,13 @@ def extra_run_arg(self, benchmark, args, image_run_args):
def extra_image_build_argument(self, benchmark, args):
extra_image_build_args = []
if benchmark == "quarkus-tika":
# Band-aid solution for class initizalization deadlock due to org.openxmlformats.schemas.drawingml.x2006 (GR-59899)
extra_image_build_args += ["-H:NumberOfThreads=1"]
extra_image_build_args += [
# Band-aid solution for class initizalization deadlock due to org.openxmlformats.schemas.drawingml.x2006 (GR-59899)
"-H:NumberOfThreads=1",
# Prevents build-time ininitialization of sun.awt.datatransfer.DesktopDatatransferServiceImpl through DefaultDesktopDatatransferService.INSTANCE
# "--initialize-at-run-time=sun.datatransfer.DataFlavorUtil$DefaultDesktopDatatransferService",
"-H:AbortOnTypeReachable=sun.datatransfer.DataFlavorUtil$DefaultDesktopDatatransferService"
]
return extra_image_build_args + super().extra_image_build_argument(benchmark, args)

def build_assertions(self, benchmark: str, is_gate: bool) -> List[str]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ public void tryRegisterNativeMethodsForBaseImage(ResolvedJavaType type) {
* Some modules contain native methods that should not be included in the image because they
* are hosted only, or because they are currently unsupported.
*/
Set<Module> forbiddenModules = hostVM.getForbiddenModules();
Set<Module> forbiddenModules = hostVM.getSharedLayerForbiddenModules();
if (forbiddenModules.contains(OriginalClassProvider.getJavaClass(type).getModule())) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ public boolean preventConstantFolding(AnalysisField aField) {
return false;
}

public Set<Module> getForbiddenModules() {
public Set<Module> getSharedLayerForbiddenModules() {
return Set.of();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,6 @@ final class LegacyReflectionConfigurationParser<C, T> extends ReflectionConfigur
super(conditionResolver, delegate, parserOptions);
}

@Override
protected EnumSet<ConfigurationParserOption> supportedOptions() {
EnumSet<ConfigurationParserOption> base = super.supportedOptions();
base.add(ConfigurationParserOption.TREAT_ALL_NAME_ENTRIES_AS_TYPE);
return base;
}

@Override
public void parseAndRegister(Object json, URI origin) {
parseClassArray(asList(json, "first level of document must be an array of class descriptors"));
Expand All @@ -64,7 +57,7 @@ public void parseAndRegister(Object json, URI origin) {
protected void parseClass(EconomicMap<String, Object> data) {
checkAttributes(data, "reflection class descriptor object", List.of(NAME_KEY), OPTIONAL_REFLECT_CONFIG_OBJECT_ATTRS);

Optional<TypeDescriptorWithOrigin> type = parseName(data, checkOption(ConfigurationParserOption.TREAT_ALL_NAME_ENTRIES_AS_TYPE));
Optional<TypeDescriptorWithOrigin> type = parseName(data, true);
if (type.isEmpty()) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import com.oracle.svm.core.option.SubstrateOptionsParser;
import com.oracle.svm.core.util.UserError;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.LogUtils;
import com.oracle.svm.util.StringUtil;

import jdk.graal.compiler.options.Option;
Expand Down Expand Up @@ -79,8 +80,10 @@ public class FutureDefaultsOptions {

private static final String RUN_TIME_INITIALIZE_SECURITY_PROVIDERS = "run-time-initialize-security-providers";
private static final String RUN_TIME_INITIALIZE_FILE_SYSTEM_PROVIDERS = "run-time-initialize-file-system-providers";
private static final List<String> ALL_FUTURE_DEFAULTS = List.of(RUN_TIME_INITIALIZE_FILE_SYSTEM_PROVIDERS, RUN_TIME_INITIALIZE_SECURITY_PROVIDERS);

private static final String COMPLETE_REFLECTION_TYPES = "complete-reflection-types";
private static final List<String> ALL_FUTURE_DEFAULTS = List.of(RUN_TIME_INITIALIZE_FILE_SYSTEM_PROVIDERS, RUN_TIME_INITIALIZE_SECURITY_PROVIDERS, COMPLETE_REFLECTION_TYPES);
private static final List<String> RETIRED_FUTURE_DEFAULTS = List.of(COMPLETE_REFLECTION_TYPES);

public static final String RUN_TIME_INITIALIZE_FILE_SYSTEM_PROVIDERS_REASON = "Initialize JDK classes at run time (--" + OPTION_NAME + " includes " + RUN_TIME_INITIALIZE_FILE_SYSTEM_PROVIDERS +
")";
Expand Down Expand Up @@ -140,6 +143,15 @@ public static void parseAndVerifyOptions() {
getOptionHelpText());
}

if (RETIRED_FUTURE_DEFAULTS.contains(value)) {
LogUtils.warning("The '%s' option from %s contains the value '%s' which is enabled by default in this GraalVM release (%s) and can be removed.",
SubstrateOptionsParser.commandArgument(FutureDefaults, value),
valueWithOrigin.origin(),
value,
VM.getVersion());
return;
}

if (!getAllValues().contains(value)) {
throw UserError.abort("The '%s' option from %s contains invalid value '%s'. It can only contain: %s.%n%nUsage:%n%n%s",
SubstrateOptionsParser.commandArgument(FutureDefaults, value),
Expand Down Expand Up @@ -169,26 +181,31 @@ public static void parseAndVerifyOptions() {

/* Set build-time properties for user features */
for (String futureDefault : getFutureDefaults()) {
System.setProperty(FutureDefaultsOptions.SYSTEM_PROPERTY_PREFIX + futureDefault, Boolean.TRUE.toString());
setSystemProperty(futureDefault, true);
}

for (String retiredFutureDefault : RETIRED_FUTURE_DEFAULTS) {
setSystemProperty(retiredFutureDefault, true);
}
}

private static void setSystemProperty(String futureDefault, boolean value) {
System.setProperty(FutureDefaultsOptions.SYSTEM_PROPERTY_PREFIX + futureDefault, Boolean.toString(value));
}

public static Set<String> getFutureDefaults() {
return Collections.unmodifiableSet(Objects.requireNonNull(futureDefaults, "must be initialized before usage"));
}

/**
* @see FutureDefaultsOptions#FutureDefaults
*/
public static boolean allFutureDefaults() {
return getFutureDefaults().containsAll(ALL_FUTURE_DEFAULTS);
public static List<String> getRetiredFutureDefaults() {
return RETIRED_FUTURE_DEFAULTS;
}

/**
* @see FutureDefaultsOptions#FutureDefaults
*/
public static boolean completeReflectionTypes() {
return getFutureDefaults().contains(COMPLETE_REFLECTION_TYPES);
public static boolean allFutureDefaults() {
return getFutureDefaults().containsAll(ALL_FUTURE_DEFAULTS);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@

import com.oracle.svm.configure.ConfigurationFile;
import com.oracle.svm.configure.ConfigurationParserOption;
import com.oracle.svm.core.FutureDefaultsOptions;
import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue;
import com.oracle.svm.core.option.BundleMember;
import com.oracle.svm.core.option.HostedOptionKey;
Expand Down Expand Up @@ -151,8 +150,8 @@ public static final class Options {
@Option(help = "Testing flag: the 'typeReachable' condition is treated as typeReached so the semantics of programs can change.")//
public static final HostedOptionKey<Boolean> TreatAllTypeReachableConditionsAsTypeReached = new HostedOptionKey<>(false);

@Option(help = "Testing flag: the 'name' is treated as 'type' in reflection configuration.")//
public static final HostedOptionKey<Boolean> TreatAllNameEntriesAsType = new HostedOptionKey<>(false);
@Option(help = "Deprecated, has no effect.", deprecated = true)//
public static final HostedOptionKey<Boolean> TreatAllNameEntriesAsType = new HostedOptionKey<>(true);

@Option(help = "Testing flag: the 'typeReached' condition is always satisfied however it prints the stack trace where it would not be satisfied.")//
public static final HostedOptionKey<Boolean> TrackUnsatisfiedTypeReachedConditions = new HostedOptionKey<>(false);
Expand Down Expand Up @@ -181,9 +180,6 @@ public static EnumSet<ConfigurationParserOption> getConfigurationParserOptions()
if (TreatAllTypeReachableConditionsAsTypeReached.getValue()) {
result.add(ConfigurationParserOption.TREAT_ALL_TYPE_REACHABLE_CONDITIONS_AS_TYPE_REACHED);
}
if (TreatAllNameEntriesAsType.getValue() || FutureDefaultsOptions.completeReflectionTypes()) {
result.add(ConfigurationParserOption.TREAT_ALL_NAME_ENTRIES_AS_TYPE);
}
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ protected SystemPropertiesSupport() {
for (String futureDefault : FutureDefaultsOptions.getFutureDefaults()) {
initializeProperty(FutureDefaultsOptions.SYSTEM_PROPERTY_PREFIX + futureDefault, Boolean.TRUE.toString());
}
for (String futureDefault : FutureDefaultsOptions.getRetiredFutureDefaults()) {
initializeProperty(FutureDefaultsOptions.SYSTEM_PROPERTY_PREFIX + futureDefault, Boolean.TRUE.toString());
}

ArrayList<LazySystemProperty> lazyProperties = new ArrayList<>();
lazyProperties.add(new LazySystemProperty(UserSystemProperty.NAME, this::userNameValue));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact 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.oracle.svm.core.reflect;

import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.reflect.target.Target_java_lang_reflect_Constructor;
import com.oracle.svm.core.reflect.target.Target_java_lang_reflect_Method;
import org.graalvm.nativeimage.impl.ReflectionIntrospector;

import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;

public class ReflectionIntrospectorImpl implements ReflectionIntrospector {
@Override
public boolean isInvocable(Executable executable) {
switch (executable) {
case Method method -> {
Target_java_lang_reflect_Method methodSubstitution = SubstrateUtil.cast(method, Target_java_lang_reflect_Method.class);
return methodSubstitution.methodAccessor != null || methodSubstitution.methodAccessorFromMetadata != null;
}
case Constructor<?> constructor -> {
Target_java_lang_reflect_Constructor constructorSubstitution = SubstrateUtil.cast(constructor, Target_java_lang_reflect_Constructor.class);
return constructorSubstitution.constructorAccessor != null || constructorSubstitution.constructorAccessorFromMetadata != null;
}
}
}
}
Loading
Loading