Skip to content

Commit 5216c9b

Browse files
committed
The -H:+CompatibilityMode for Native Image
The goal of this mode is to remove native-image implementation-specific behavior: no build-time initialization on classpath, no custom system properties for native image, no substitutions on classpath, no user features, future defaults enabled by default. It still does not modify the key restrictions of Native Image which are related to dynamic access and run-time class loading. Also, this mode still does not disable flags such as --features and --initialize-at-build-time from the command line. This will be discussed separately and done in a separate PR. To get the same behavior as the underlying language it is recommended to use this flag with: native-image -H:+CompatibilityMode -H:Preserve=all -H:+RuntimeClassLoading App And to run it with: ./app -Djava.home=<path-to-java-home> -Djava.class.path=<cp> -Djdk.module.path=<module-path>
1 parent 2a8a8d3 commit 5216c9b

18 files changed

Lines changed: 294 additions & 51 deletions

File tree

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#
2+
# Copyright (c) 2026, 2026, Oracle and/or its affiliates. All rights reserved.
3+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
#
5+
# The Universal Permissive License (UPL), Version 1.0
6+
#
7+
# Subject to the condition set forth below, permission is hereby granted to any
8+
# person obtaining a copy of this software, associated documentation and/or
9+
# data (collectively the "Software"), free of charge and under any and all
10+
# copyright rights in the Software, and any and all patent rights owned or
11+
# freely licensable by each licensor hereunder covering either (i) the
12+
# unmodified Software as contributed to or provided by such licensor, or (ii)
13+
# the Larger Works (as defined below), to deal in both
14+
#
15+
# (a) the Software, and
16+
#
17+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
# one is included with the Software each a "Larger Work" to which the Software
19+
# is contributed by such licensors),
20+
#
21+
# without restriction, including without limitation the rights to copy, create
22+
# derivative works of, display, perform, and distribute the Software and make,
23+
# use, sell, offer for sale, import, export, have made, and have sold the
24+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
# either these or other terms.
26+
#
27+
# This license is subject to the following condition:
28+
#
29+
# The above copyright notice and either this complete permission notice or at a
30+
# minimum a reference to the UPL must be included in all copies or substantial
31+
# portions of the Software.
32+
#
33+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
# SOFTWARE.
40+
#
41+
name: Weekly Micronaut Tests (-H:+CompatibilityMode -H:Preserve=all -H:+RuntimeClassLoading)
42+
43+
on:
44+
pull_request:
45+
paths:
46+
- '.github/workflows/micronaut-template.yml'
47+
- '.github/workflows/micronaut-compatibility-preserve.yml'
48+
schedule:
49+
- cron: '0 2 * * 1'
50+
workflow_dispatch:
51+
52+
jobs:
53+
call-template:
54+
uses: './.github/workflows/micronaut-template.yml'
55+
with:
56+
NATIVE_IMAGE_OPTIONS: '-H:+UnlockExperimentalVMOptions -H:+ReportExceptionStackTraces -H:+CompatibilityMode -H:Preserve=all -H:+RuntimeClassLoading -H:-UnlockExperimentalVMOptions'

.github/workflows/micronaut-template.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ env:
5252
MICRONAUT_JAVA_VERSION: 21
5353
# Enforce experimental option checking in CI (GR-47922)
5454
NATIVE_IMAGE_EXPERIMENTAL_OPTIONS_ARE_FATAL: 'true'
55-
NATIVE_IMAGE_OPTIONS: ${{ inputs.NATIVE_IMAGE_OPTIONS }}
5655

5756
permissions:
5857
contents: read # to fetch code (actions/checkout)
@@ -69,7 +68,9 @@ jobs:
6968
uses: ./.github/actions/build-graalvm
7069
with:
7170
java-version: ${{ env.MICRONAUT_JAVA_VERSION }}
72-
- name: Run nativeTest in Micronaut launch project
71+
- name: Run nativeTest in Micronaut launch project${{ inputs.NATIVE_IMAGE_OPTIONS && format(' with ''{0}''', inputs.NATIVE_IMAGE_OPTIONS) || '' }}
72+
env:
73+
NATIVE_IMAGE_OPTIONS: ${{ inputs.NATIVE_IMAGE_OPTIONS }}
7374
run: |
7475
curl --fail --silent --location --retry 3 --max-time 10 --output demo.zip --request GET 'https://launch.micronaut.io/create/default/com.example.demo?lang=JAVA&build=GRADLE&test=JUNIT&javaVersion=JDK_${{ env.MICRONAUT_JAVA_VERSION }}'
7576
unzip demo.zip
@@ -81,6 +82,8 @@ jobs:
8182
repository: micronaut-projects/micronaut-core
8283
path: ${{ env.MICRONAUT_CORE_PATH }}
8384
- name: Run nativeTest in micronaut-core${{ inputs.NATIVE_IMAGE_OPTIONS && format(' with ''{0}''', inputs.NATIVE_IMAGE_OPTIONS) || '' }}
85+
env:
86+
NATIVE_IMAGE_OPTIONS: ${{ inputs.NATIVE_IMAGE_OPTIONS }}
8487
run: |
8588
cd ${{ env.MICRONAUT_CORE_PATH }}
8689
./gradlew nativeTest
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#
2+
# Copyright (c) 2026, 2026, Oracle and/or its affiliates. All rights reserved.
3+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
#
5+
# The Universal Permissive License (UPL), Version 1.0
6+
#
7+
# Subject to the condition set forth below, permission is hereby granted to any
8+
# person obtaining a copy of this software, associated documentation and/or
9+
# data (collectively the "Software"), free of charge and under any and all
10+
# copyright rights in the Software, and any and all patent rights owned or
11+
# freely licensable by each licensor hereunder covering either (i) the
12+
# unmodified Software as contributed to or provided by such licensor, or (ii)
13+
# the Larger Works (as defined below), to deal in both
14+
#
15+
# (a) the Software, and
16+
#
17+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
# one is included with the Software each a "Larger Work" to which the Software
19+
# is contributed by such licensors),
20+
#
21+
# without restriction, including without limitation the rights to copy, create
22+
# derivative works of, display, perform, and distribute the Software and make,
23+
# use, sell, offer for sale, import, export, have made, and have sold the
24+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
# either these or other terms.
26+
#
27+
# This license is subject to the following condition:
28+
#
29+
# The above copyright notice and either this complete permission notice or at a
30+
# minimum a reference to the UPL must be included in all copies or substantial
31+
# portions of the Software.
32+
#
33+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
# SOFTWARE.
40+
#
41+
name: Weekly Reachability Metadata Tests (-H:+CompatibilityMode -H:Preserve=all -H:+RuntimeClassLoading)
42+
43+
on:
44+
pull_request:
45+
paths:
46+
- '.github/workflows/reachability-metadata-template.yml'
47+
- '.github/workflows/reachability-metadata-compatibility-preserve.yml'
48+
schedule:
49+
- cron: '0 1 * * 1'
50+
workflow_dispatch:
51+
52+
jobs:
53+
call-template:
54+
uses: './.github/workflows/reachability-metadata-template.yml'
55+
with:
56+
NATIVE_IMAGE_OPTIONS: '-H:+UnlockExperimentalVMOptions -H:+ReportExceptionStackTraces -H:+CompatibilityMode -H:Preserve=all -H:+RuntimeClassLoading -H:-UnlockExperimentalVMOptions'

docs/reference-manual/native-image/guides/troubleshoot-run-time-errors.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,20 @@ For diagnosing shared libraries built with Native Image, you can either:
4141
* specify `-R:MissingRegistrationReportingMode=Exit` when building a native shared library;
4242
* or specify `-XX:MissingRegistrationReportingMode=Exit` when the isolate is created. `graal_create_isolate_params_t` has `argc` and `argv` fields that can be used to pass C-style command-line options at run time.
4343

44-
### 2. Set java.home Explicitly
44+
### 2. Set java.home and Classpath Explicitly
4545

4646
If your application code uses the `java.home` property, set it explicitly with `-Djava.home=<path>` when running a native executable.
47-
Otherwise, the `System.getProperty("java.home")` call will return a `null` value.
47+
Otherwise, the `System.getProperty("java.home")` call will return a `null` value. For instance, you can run your native executable like this:
48+
49+
```console
50+
./my-native-app -Djava.home=/path/to/jdk
51+
```
52+
53+
Some applications also need access to the classpath and module path at run time. Those can be set with `-Djava.class.path=<class-path>` and `-Djdk.module.path=<module-path>` when running the executable. Here's how you would specify both properties:
54+
55+
```console
56+
./my-native-app -Djava.class.path=/path/to/classes:/path/to/lib.jar -Djdk.module.path=/path/to/modules
57+
```
4858

4959
### 3. Enable URL Protocols
5060

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -161,7 +161,7 @@ public static boolean inImageBuildtimeCode() {
161161
*/
162162
public static boolean isExecutable() {
163163
ensureKindAvailable();
164-
return PROPERTY_IMAGE_KIND_VALUE_EXECUTABLE.equals(System.getProperty(PROPERTY_IMAGE_KIND_KEY));
164+
return PROPERTY_IMAGE_KIND_VALUE_EXECUTABLE.equals(ImageKindHolder.IMAGE_KIND);
165165
}
166166

167167
/**
@@ -171,13 +171,21 @@ public static boolean isExecutable() {
171171
*/
172172
public static boolean isSharedLibrary() {
173173
ensureKindAvailable();
174-
return PROPERTY_IMAGE_KIND_VALUE_SHARED_LIBRARY.equals(System.getProperty(PROPERTY_IMAGE_KIND_KEY));
174+
return PROPERTY_IMAGE_KIND_VALUE_SHARED_LIBRARY.equals(ImageKindHolder.IMAGE_KIND);
175175
}
176176

177177
private static void ensureKindAvailable() {
178-
if (inImageCode() && System.getProperty(PROPERTY_IMAGE_KIND_KEY) == null) {
178+
if (inImageCode() && ImageKindHolder.IMAGE_KIND == null) {
179179
throw new UnsupportedOperationException(
180180
"The kind of image that is built (executable or shared library) is not available yet because the relevant command line option has not been parsed yet.");
181181
}
182182
}
183+
184+
/// This class is needed so [#IMAGE_KIND] does not get initialized before the
185+
/// [#PROPERTY_IMAGE_KIND_KEY] property is set.
186+
/// [ImageInfo] is initialized very early in the build process before the
187+
/// [#PROPERTY_IMAGE_KIND_KEY] property is set by the image builder.
188+
private static final class ImageKindHolder {
189+
static final String IMAGE_KIND = System.getProperty(PROPERTY_IMAGE_KIND_KEY);
190+
}
183191
}

substratevm/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ This changelog summarizes major changes to GraalVM Native Image.
2424
* (GR-63737) Deprecated API function `Threading.registerRecurringCallback(...)` without replacement. This method should not be used as it is inherently unsafe.
2525
* (GR-63737) Removed deprecated API function `ProcessPropertiesSupport.setLocale(...)`.
2626
* (GR-52538) (GR-69523) (GR-73129) Introduce new SerialGC policy `Adaptive2` and default to mark-compact collection in the old generation. On average, this reduces memory usage and often improves throughput and latency. Restore the old behavior with: `-H:-CompactingOldGen -H:InitialCollectionPolicy=Adaptive`.
27+
* (GR-71974) Introduced `-H:+CompatibilityMode` that disables all Native Image features that allow users to diverge from original program semantics: build-time initialization for classpath classes, native-image-specific system properties, substitutions on the classpath, and user features, while enabling all future defaults. This mode does not modify key Native Image restrictions related to dynamic access (reachability metadata) and run-time class loading as those are accepted limitations of native image.
2728

2829
## GraalVM 25
2930
* (GR-52276) (GR-61959) Add support for Arena.ofShared().

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSystemPropertiesSupport.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,19 @@
2626

2727
import org.graalvm.nativeimage.c.type.CCharPointer;
2828
import org.graalvm.nativeimage.c.type.CTypeConversion;
29+
import org.graalvm.word.impl.Word;
2930

3031
import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue;
3132
import com.oracle.svm.core.jdk.SystemPropertiesSupport;
3233
import com.oracle.svm.core.posix.headers.Limits;
3334
import com.oracle.svm.core.posix.headers.Unistd;
34-
import org.graalvm.word.impl.Word;
3535

3636
public abstract class PosixSystemPropertiesSupport extends SystemPropertiesSupport {
3737

38+
public PosixSystemPropertiesSupport(boolean compatibilityMode) {
39+
super(compatibilityMode);
40+
}
41+
3842
@Override
3943
protected String jvmLibName() {
4044
return "libjvm" + jvmLibSuffix();

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinSystemPropertiesSupport.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
package com.oracle.svm.core.posix.darwin;
2626

27+
import com.oracle.svm.hosted.NativeImageOptions;
2728
import org.graalvm.nativeimage.ImageSingletons;
2829
import org.graalvm.nativeimage.Platform;
2930
import org.graalvm.nativeimage.c.function.CLibrary;
@@ -32,6 +33,7 @@
3233
import org.graalvm.nativeimage.c.type.CTypeConversion.CCharPointerHolder;
3334
import org.graalvm.nativeimage.impl.RuntimeSystemPropertiesSupport;
3435
import org.graalvm.word.UnsignedWord;
36+
import org.graalvm.word.impl.Word;
3537

3638
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
3739
import com.oracle.svm.core.feature.InternalFeature;
@@ -43,17 +45,20 @@
4345
import com.oracle.svm.core.posix.headers.Stdlib;
4446
import com.oracle.svm.core.posix.headers.Unistd;
4547
import com.oracle.svm.core.posix.headers.darwin.Foundation;
48+
import com.oracle.svm.shared.singletons.traits.SingletonTraits;
4649
import com.oracle.svm.shared.singletons.traits.BuiltinTraits.AllAccess;
4750
import com.oracle.svm.shared.singletons.traits.BuiltinTraits.BuildtimeAccessOnly;
4851
import com.oracle.svm.shared.singletons.traits.BuiltinTraits.Disallowed;
4952
import com.oracle.svm.shared.singletons.traits.BuiltinTraits.NoLayeredCallbacks;
50-
import com.oracle.svm.shared.singletons.traits.SingletonTraits;
51-
import org.graalvm.word.impl.Word;
5253

5354
@SingletonTraits(access = AllAccess.class, layeredCallbacks = NoLayeredCallbacks.class, other = Disallowed.class)
5455
@CLibrary(value = "darwin", requireStatic = true)
5556
public class DarwinSystemPropertiesSupport extends PosixSystemPropertiesSupport {
5657

58+
public DarwinSystemPropertiesSupport(boolean compatibilityMode) {
59+
super(compatibilityMode);
60+
}
61+
5762
@Override
5863
protected String javaIoTmpdirValue() {
5964
/* Darwin has a per-user temp dir */
@@ -143,7 +148,8 @@ protected String jvmLibSuffix() {
143148
class DarwinSystemPropertiesFeature implements InternalFeature {
144149
@Override
145150
public void duringSetup(DuringSetupAccess access) {
146-
ImageSingletons.add(RuntimeSystemPropertiesSupport.class, new DarwinSystemPropertiesSupport());
151+
ImageSingletons.add(RuntimeSystemPropertiesSupport.class,
152+
new DarwinSystemPropertiesSupport(NativeImageOptions.compatibilityMode()));
147153
ImageSingletons.add(SystemPropertiesSupport.class, (SystemPropertiesSupport) ImageSingletons.lookup(RuntimeSystemPropertiesSupport.class));
148154
}
149155
}

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxSystemPropertiesSupport.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,20 @@
3838
import com.oracle.svm.core.posix.PosixSystemPropertiesSupport;
3939
import com.oracle.svm.core.posix.headers.Stdlib;
4040
import com.oracle.svm.core.posix.headers.Utsname;
41+
import com.oracle.svm.hosted.NativeImageOptions;
42+
import com.oracle.svm.shared.singletons.traits.SingletonTraits;
4143
import com.oracle.svm.shared.singletons.traits.BuiltinTraits.AllAccess;
4244
import com.oracle.svm.shared.singletons.traits.BuiltinTraits.BuildtimeAccessOnly;
4345
import com.oracle.svm.shared.singletons.traits.BuiltinTraits.SingleLayer;
4446
import com.oracle.svm.shared.singletons.traits.SingletonLayeredInstallationKind.InitialLayerOnly;
45-
import com.oracle.svm.shared.singletons.traits.SingletonTraits;
4647

4748
@SingletonTraits(access = AllAccess.class, layeredCallbacks = SingleLayer.class, layeredInstallationKind = InitialLayerOnly.class)
4849
public class LinuxSystemPropertiesSupport extends PosixSystemPropertiesSupport {
4950

51+
public LinuxSystemPropertiesSupport(boolean compatibilityMode) {
52+
super(compatibilityMode);
53+
}
54+
5055
@Override
5156
protected String javaIoTmpdirValue() {
5257
/*
@@ -110,7 +115,7 @@ public boolean isInConfiguration(IsInConfigurationAccess access) {
110115

111116
@Override
112117
public void duringSetup(DuringSetupAccess access) {
113-
LinuxSystemPropertiesSupport singleton = new LinuxSystemPropertiesSupport();
118+
LinuxSystemPropertiesSupport singleton = new LinuxSystemPropertiesSupport(NativeImageOptions.compatibilityMode());
114119
ImageSingletons.add(RuntimeSystemPropertiesSupport.class, singleton);
115120
ImageSingletons.add(SystemPropertiesSupport.class, singleton);
116121
}

substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSystemPropertiesSupport.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.graalvm.nativeimage.c.type.WordPointer;
3838
import org.graalvm.nativeimage.impl.RuntimeSystemPropertiesSupport;
3939
import org.graalvm.word.UnsignedWord;
40+
import org.graalvm.word.impl.Word;
4041

4142
import com.oracle.svm.core.c.NonmovableArrays;
4243
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
@@ -60,7 +61,7 @@
6061
import com.oracle.svm.core.windows.headers.WinVer;
6162
import com.oracle.svm.core.windows.headers.WindowsLibC;
6263
import com.oracle.svm.core.windows.headers.WindowsLibC.WCharPointer;
63-
import org.graalvm.word.impl.Word;
64+
import com.oracle.svm.hosted.NativeImageOptions;
6465

6566
@SingletonTraits(access = AllAccess.class, layeredCallbacks = NoLayeredCallbacks.class, other = Disallowed.class)
6667
public class WindowsSystemPropertiesSupport extends SystemPropertiesSupport {
@@ -74,6 +75,10 @@ public class WindowsSystemPropertiesSupport extends SystemPropertiesSupport {
7475
private static final int VER_PLATFORM_WIN32_WINDOWS = 1;
7576
private static final int VER_PLATFORM_WIN32_NT = 2;
7677

78+
public WindowsSystemPropertiesSupport(boolean compatibilityMode) {
79+
super(compatibilityMode);
80+
}
81+
7782
@Override
7883
protected String userNameValue() {
7984
WCharPointer userName = WindowsLibC._wgetenv(NonmovableArrays.addressOf(NonmovableArrays.fromImageHeap(USERNAME), 0));
@@ -406,7 +411,8 @@ private void computeOsNameAndVersion() {
406411
class WindowsSystemPropertiesFeature implements InternalFeature {
407412
@Override
408413
public void duringSetup(DuringSetupAccess access) {
409-
ImageSingletons.add(RuntimeSystemPropertiesSupport.class, new WindowsSystemPropertiesSupport());
414+
ImageSingletons.add(RuntimeSystemPropertiesSupport.class,
415+
new WindowsSystemPropertiesSupport(NativeImageOptions.compatibilityMode()));
410416
ImageSingletons.add(SystemPropertiesSupport.class, (SystemPropertiesSupport) ImageSingletons.lookup(RuntimeSystemPropertiesSupport.class));
411417
}
412418
}

0 commit comments

Comments
 (0)