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