2525package com .oracle .svm .hosted ;
2626
2727import java .io .File ;
28+ import java .io .IOException ;
2829import java .lang .module .Configuration ;
2930import java .lang .module .ModuleDescriptor ;
3031import java .lang .module .ModuleFinder ;
32+ import java .lang .module .ModuleReader ;
33+ import java .lang .module .ModuleReference ;
3134import java .nio .file .Path ;
3235import java .nio .file .Paths ;
36+ import java .util .ArrayDeque ;
37+ import java .util .ArrayList ;
3338import java .util .Arrays ;
3439import java .util .Collections ;
40+ import java .util .Deque ;
41+ import java .util .HashMap ;
3542import java .util .HashSet ;
3643import java .util .List ;
44+ import java .util .Map ;
3745import java .util .Objects ;
3846import java .util .Optional ;
3947import java .util .Set ;
4856import com .oracle .svm .core .option .SubstrateOptionsParser ;
4957import com .oracle .svm .core .util .UserError ;
5058import com .oracle .svm .core .util .VMError ;
51- import com .oracle .svm .util .ModuleSupport ;
5259
5360import jdk .internal .module .Modules ;
5461
@@ -59,22 +66,28 @@ public class NativeImageClassLoaderSupport extends AbstractNativeImageClassLoade
5966
6067 private final ClassLoader classLoader ;
6168 private final ModuleLayer moduleLayerForImageBuild ;
69+ private final Map <String , Set <Module >> packageToModuleNames ;
6270
6371 NativeImageClassLoaderSupport (ClassLoader defaultSystemClassLoader , String [] classpath , String [] modulePath ) {
6472 super (defaultSystemClassLoader , classpath );
6573
74+ packageToModuleNames = new HashMap <>();
75+
6676 imagemp = Arrays .stream (modulePath ).map (Paths ::get ).collect (Collectors .toUnmodifiableList ());
6777 buildmp = Arrays .stream (System .getProperty ("jdk.module.path" , "" ).split (File .pathSeparator )).map (Paths ::get ).collect (Collectors .toUnmodifiableList ());
6878
6979 ModuleLayer moduleLayer = createModuleLayer (imagemp .toArray (Path []::new ), classPathClassLoader );
70- if (moduleLayer . modules (). isEmpty ()) {
71- this . moduleLayerForImageBuild = null ;
72- classLoader = classPathClassLoader ;
73- } else {
74- adjustBootLayerQualifiedExports ( moduleLayer );
75- this . moduleLayerForImageBuild = moduleLayer ;
76- classLoader = getSingleClassloader ( moduleLayer );
80+ adjustBootLayerQualifiedExports (moduleLayer );
81+ for ( ModuleLayer layer : allLayers ( moduleLayer )) {
82+ for ( Module module : layer . modules ()) {
83+ for ( String packageName : module . getDescriptor (). packages ()) {
84+ addToPackageNameModules ( module , packageName );
85+ }
86+ }
7787 }
88+ // dumpPackageNameModulesMapping();
89+ moduleLayerForImageBuild = moduleLayer ;
90+ classLoader = getSingleClassloader (moduleLayer );
7891 }
7992
8093 private static ModuleLayer createModuleLayer (Path [] modulePaths , ClassLoader parent ) {
@@ -89,6 +102,56 @@ private static ModuleLayer createModuleLayer(Path[] modulePaths, ClassLoader par
89102 return ModuleLayer .defineModulesWithOneLoader (configuration , List .of (ModuleLayer .boot ()), parent ).layer ();
90103 }
91104
105+ private List <ModuleLayer > allLayers (ModuleLayer moduleLayer ) {
106+ /** Implementation taken from {@link ModuleLayer#layers()} */
107+ List <ModuleLayer > allLayers = new ArrayList <>();
108+ Set <ModuleLayer > visited = new HashSet <>();
109+ Deque <ModuleLayer > stack = new ArrayDeque <>();
110+ visited .add (moduleLayer );
111+ stack .push (moduleLayer );
112+
113+ while (!stack .isEmpty ()) {
114+ ModuleLayer layer = stack .pop ();
115+ allLayers .add (layer );
116+
117+ // push in reverse order
118+ for (int i = layer .parents ().size () - 1 ; i >= 0 ; i --) {
119+ ModuleLayer parent = layer .parents ().get (i );
120+ if (!visited .contains (parent )) {
121+ visited .add (parent );
122+ stack .push (parent );
123+ }
124+ }
125+ }
126+ return allLayers ;
127+ }
128+
129+ private void addToPackageNameModules (Module moduleName , String packageName ) {
130+ Set <Module > prevValue = packageToModuleNames .get (packageName );
131+ if (prevValue == null ) {
132+ /* Mostly packageName is only used in a single module */
133+ packageToModuleNames .put (packageName , Collections .singleton (moduleName ));
134+ } else if (prevValue .size () == 1 ) {
135+ /* Transition to HashSet - happens rarely */
136+ HashSet <Module > newValue = new HashSet <>();
137+ newValue .add (prevValue .iterator ().next ());
138+ newValue .add (moduleName );
139+ packageToModuleNames .put (packageName , newValue );
140+ } else if (prevValue .size () > 1 ) {
141+ /* Add to exiting HashSet - happens rarely */
142+ prevValue .add (moduleName );
143+ }
144+ }
145+
146+ public void dumpPackageNameModulesMapping () {
147+ packageToModuleNames .entrySet ().stream ()
148+ .sorted (Map .Entry .comparingByKey ())
149+ .map (e -> e .getKey () + " -> " + e .getValue ().stream ()
150+ .map (Module ::getName )
151+ .collect (Collectors .joining (", " )))
152+ .forEach (System .out ::println );
153+ }
154+
92155 private void adjustBootLayerQualifiedExports (ModuleLayer layer ) {
93156 /*
94157 * For all qualified exports packages of modules in the the boot layer we check if layer
@@ -137,9 +200,6 @@ List<Path> applicationModulePath() {
137200
138201 @ Override
139202 public Optional <Module > findModule (String moduleName ) {
140- if (moduleLayerForImageBuild == null ) {
141- return Optional .empty ();
142- }
143203 return moduleLayerForImageBuild .findModule (moduleName );
144204 }
145205
@@ -227,79 +287,67 @@ private static UserError.UserException userErrorAddExportsAndOpens(String origin
227287
228288 @ Override
229289 Class <?> loadClassFromModule (Object module , String className ) throws ClassNotFoundException {
230- if (module == null ) {
231- return Class .forName (className , false , classPathClassLoader );
232- }
233- if (!(module instanceof Module )) {
234- throw new IllegalArgumentException ("Argument `module` is not an instance of java.lang.Module" );
235- }
290+ assert module instanceof Module : "Argument `module` is not an instance of java.lang.Module" ;
236291 Module m = (Module ) module ;
237- if (m .getClassLoader () != classLoader ) {
238- throw new IllegalArgumentException ("Argument `module` is java.lang.Module from different ClassLoader" );
239- }
240- String moduleClassName = className ;
241- if (moduleClassName .isEmpty ()) {
242- moduleClassName = m .getDescriptor ().mainClass ().orElseThrow (
243- () -> UserError .abort ("module %s does not have a ModuleMainClass attribute, use -m <module>/<main-class>" , m .getName ()));
244- }
245- Class <?> clazz = Class .forName (m , moduleClassName );
246- if (clazz == null ) {
247- throw new ClassNotFoundException (moduleClassName );
248- }
249- return clazz ;
292+ assert m .getClassLoader () == classLoader : "Argument `module` is java.lang.Module from different ClassLoader" ;
293+ return Class .forName (m , className );
294+ }
295+
296+ @ Override
297+ Optional <String > getMainClassFromModule (Object module ) {
298+ assert module instanceof Module : "Argument `module` is not an instance of java.lang.Module" ;
299+ return ((Module ) module ).getDescriptor ().mainClass ();
250300 }
251301
252302 @ Override
253303 ClassLoader getClassLoader () {
254304 return classLoader ;
255305 }
256306
257- private static class ClassInitWithModules extends ClassInit {
307+ private class ClassInitWithModules extends ClassInit {
258308
259- ClassInitWithModules (ForkJoinPool executor , ImageClassLoader imageClassLoader , AbstractNativeImageClassLoaderSupport nativeImageClassLoader ) {
260- super (executor , imageClassLoader , nativeImageClassLoader );
309+ ClassInitWithModules (ForkJoinPool executor , ImageClassLoader imageClassLoader ) {
310+ super (executor , imageClassLoader );
261311 }
262312
263313 @ Override
264314 protected void init () {
265- Set <String > modules = new HashSet <>();
266- modules .add ("jdk.internal.vm.ci" );
267-
268- addOptionalModule (modules , "org.graalvm.sdk" );
269- addOptionalModule (modules , "jdk.internal.vm.compiler" );
270- addOptionalModule (modules , "com.oracle.graal.graal_enterprise" );
315+ List <String > requiresInit = Arrays .asList (
316+ "jdk.internal.vm.ci" , "jdk.internal.vm.compiler" , "com.oracle.graal.graal_enterprise" ,
317+ "org.graalvm.sdk" , "org.graalvm.truffle" );
271318
272- String includeModulesStr = System .getProperty (PROPERTY_IMAGEINCLUDEBUILTINMODULES );
273- if (includeModulesStr != null ) {
274- modules .addAll (Arrays .asList (includeModulesStr .split ("," )));
275- }
276-
277- for (String moduleResource : ModuleSupport .getSystemModuleResources (modules )) {
278- handleClassInModuleResource (moduleResource );
319+ for (ModuleReference moduleReference : ModuleFinder .ofSystem ().findAll ()) {
320+ if (requiresInit .contains (moduleReference .descriptor ().name ())) {
321+ initModule (moduleReference );
322+ }
279323 }
280-
281- for (String moduleResource : ModuleSupport .getModuleResources (nativeImageClassLoader .modulepath ())) {
282- handleClassInModuleResource (moduleResource );
324+ for (ModuleReference moduleReference : ModuleFinder .of (modulepath ().toArray (Path []::new )).findAll ()) {
325+ initModule (moduleReference );
283326 }
284327
285328 super .init ();
286329 }
287330
288- private void handleClassInModuleResource (String moduleResource ) {
289- if (moduleResource .endsWith (CLASS_EXTENSION )) {
290- executor .execute (() -> handleClassFileName (classFileWithoutSuffix (moduleResource ), '/' ));
331+ private void initModule (ModuleReference moduleReference ) {
332+ Optional <Module > optionalModule = findModule (moduleReference .descriptor ().name ());
333+ if (optionalModule .isEmpty ()) {
334+ return ;
291335 }
292- }
293-
294- private static void addOptionalModule (Set <String > modules , String name ) {
295- if (ModuleSupport .hasSystemModule (name )) {
296- modules .add (name );
336+ try (ModuleReader moduleReader = moduleReference .open ()) {
337+ Module module = optionalModule .get ();
338+ moduleReader .list ().forEach (moduleResource -> {
339+ if (moduleResource .endsWith (CLASS_EXTENSION )) {
340+ executor .execute (() -> handleClassFileName (module , moduleResource , '/' ));
341+ }
342+ });
343+ } catch (IOException e ) {
344+ throw new RuntimeException ("Unable get list of resources in module" + moduleReference .descriptor ().name (), e );
297345 }
298346 }
299347 }
300348
301349 @ Override
302350 public void initAllClasses (ForkJoinPool executor , ImageClassLoader imageClassLoader ) {
303- new ClassInitWithModules (executor , imageClassLoader , this ).init ();
351+ new ClassInitWithModules (executor , imageClassLoader ).init ();
304352 }
305353}
0 commit comments