|
71 | 71 | import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
|
72 | 72 | import org.graalvm.compiler.options.Option;
|
73 | 73 | import org.graalvm.compiler.options.OptionType;
|
74 |
| -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; |
75 | 74 | import org.graalvm.nativeimage.ImageSingletons;
|
76 | 75 | import org.graalvm.nativeimage.Platform;
|
77 | 76 | import org.graalvm.nativeimage.Platforms;
|
@@ -168,7 +167,7 @@ public static class Options {
|
168 | 167 | public static final HostedOptionKey<Boolean> IncludeAllLocales = new HostedOptionKey<>(false);
|
169 | 168 |
|
170 | 169 | @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); |
172 | 171 |
|
173 | 172 | @Option(help = "Store the resource bundle content more efficiently in the fallback mode.", type = OptionType.User)//
|
174 | 173 | public static final HostedOptionKey<Boolean> LocalizationSubstituteLoadLookup = new HostedOptionKey<>(true);
|
@@ -260,6 +259,40 @@ public void afterRegistration(AfterRegistrationAccess access) {
|
260 | 259 | }
|
261 | 260 | }
|
262 | 261 |
|
| 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 | + |
263 | 296 | @Platforms(Platform.HOSTED_ONLY.class)
|
264 | 297 | private LocalizationSupport selectLocalizationSupport() {
|
265 | 298 | if (optimizedMode) {
|
|
0 commit comments