Skip to content

Commit 7b25f37

Browse files
committed
register an object replacer for ResourceBundles
1 parent 56374f6 commit 7b25f37

File tree

1 file changed

+35
-2
lines changed

1 file changed

+35
-2
lines changed

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/LocalizationFeature.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@
7171
import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
7272
import org.graalvm.compiler.options.Option;
7373
import org.graalvm.compiler.options.OptionType;
74-
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
7574
import org.graalvm.nativeimage.ImageSingletons;
7675
import org.graalvm.nativeimage.Platform;
7776
import org.graalvm.nativeimage.Platforms;
@@ -168,7 +167,7 @@ public static class Options {
168167
public static final HostedOptionKey<Boolean> IncludeAllLocales = new HostedOptionKey<>(false);
169168

170169
@Option(help = "Optimize the resource bundle lookup using a simple map.", type = OptionType.User)//
171-
public static final HostedOptionKey<Boolean> LocalizationOptimizedMode = new HostedOptionKey<>(JavaVersionUtil.JAVA_SPEC == 8);
170+
public static final HostedOptionKey<Boolean> LocalizationOptimizedMode = new HostedOptionKey<>(true);
172171

173172
@Option(help = "Store the resource bundle content more efficiently in the fallback mode.", type = OptionType.User)//
174173
public static final HostedOptionKey<Boolean> LocalizationSubstituteLoadLookup = new HostedOptionKey<>(true);
@@ -260,6 +259,40 @@ public void afterRegistration(AfterRegistrationAccess access) {
260259
}
261260
}
262261

262+
@Override
263+
public void duringSetup(DuringSetupAccess access) {
264+
if (optimizedMode) {
265+
access.registerObjectReplacer(this::eagerlyInitializeBundles);
266+
}
267+
}
268+
269+
/**
270+
* In the optimized localization support, the bundles are stored in a map. In order to make the
271+
* getContents methods unreachable, the bundles are initialized eagerly and the lookup methods
272+
* are substituted. However, if there are bundle instances somewhere in the heap that were not
273+
* put in the map, they won't be initialized and therefore accessing their content will cause
274+
* runtime failures. Therefore, we visit each object in the heap and if it is a ResourceBundle,
275+
* we eagerly initialize it.
276+
*/
277+
private Object eagerlyInitializeBundles(Object object) {
278+
assert optimizedMode : "Should only be triggered in the optimized mode.";
279+
if (object instanceof ResourceBundle) {
280+
ResourceBundle bundle = (ResourceBundle) object;
281+
try {
282+
/*
283+
* getKeys can be null for ResourceBundle.NONEXISTENT_BUNDLE, which causes the
284+
* keySet method to crash.
285+
*/
286+
if (bundle.getKeys() != null) {
287+
bundle.keySet();
288+
}
289+
} catch (Exception ex) {
290+
trace("Failed to eagerly initialize bundle " + bundle + ", " + bundle.getBaseBundleName() + ", reason " + ex.getClass() + " " + ex.getMessage());
291+
}
292+
}
293+
return object;
294+
}
295+
263296
@Platforms(Platform.HOSTED_ONLY.class)
264297
private LocalizationSupport selectLocalizationSupport() {
265298
if (optimizedMode) {

0 commit comments

Comments
 (0)