@@ -120,6 +120,8 @@ public final class SystemModulesPlugin extends AbstractPlugin {
120
120
ClassDesc .ofInternalName (SYSTEM_MODULES_MAP_CLASSNAME );
121
121
private static final MethodTypeDesc MTD_StringArray = MethodTypeDesc .of (CD_String .arrayType ());
122
122
private static final MethodTypeDesc MTD_SystemModules = MethodTypeDesc .of (CD_SYSTEM_MODULES );
123
+
124
+ private int moduleDescriptorsPerMethod = 75 ;
123
125
private boolean enabled ;
124
126
125
127
public SystemModulesPlugin () {
@@ -142,7 +144,14 @@ public boolean hasArguments() {
142
144
public void configure (Map <String , String > config ) {
143
145
String arg = config .get (getName ());
144
146
if (arg != null ) {
145
- throw new IllegalArgumentException (getName () + ": " + arg );
147
+ String [] split = arg .split ("=" );
148
+ if (split .length != 2 ) {
149
+ throw new IllegalArgumentException (getName () + ": " + arg );
150
+ }
151
+ if (split [0 ].equals ("batch-size" )) {
152
+ throw new IllegalArgumentException (getName () + ": " + arg );
153
+ }
154
+ this .moduleDescriptorsPerMethod = Integer .parseInt (split [1 ]);
146
155
}
147
156
}
148
157
@@ -318,7 +327,7 @@ private String genSystemModulesClass(List<ModuleInfo> moduleInfos,
318
327
String className ,
319
328
ResourcePoolBuilder out ) {
320
329
SystemModulesClassGenerator generator
321
- = new SystemModulesClassGenerator (className , moduleInfos );
330
+ = new SystemModulesClassGenerator (className , moduleInfos , moduleDescriptorsPerMethod );
322
331
byte [] bytes = generator .genClassBytes (cf );
323
332
String rn = "/java.base/" + className + ".class" ;
324
333
ResourcePoolEntry e = ResourcePoolEntry .create (rn , bytes );
@@ -533,28 +542,33 @@ static class SystemModulesClassGenerator {
533
542
534
543
private static final int MAX_LOCAL_VARS = 256 ;
535
544
536
- private final int BUILDER_VAR = 0 ;
537
545
private final int MD_VAR = 1 ; // variable for ModuleDescriptor
538
546
private final int MT_VAR = 1 ; // variable for ModuleTarget
539
547
private final int MH_VAR = 1 ; // variable for ModuleHashes
540
- private int nextLocalVar = 2 ; // index to next local variable
548
+ private final int DEDUP_LIST_VAR = 2 ;
549
+ private final int BUILDER_VAR = 3 ;
550
+ private int nextLocalVar = 4 ; // index to next local variable
541
551
542
552
// name of class to generate
543
553
private final ClassDesc classDesc ;
544
554
545
555
// list of all ModuleInfos
546
556
private final List <ModuleInfo > moduleInfos ;
547
557
558
+ private final int moduleDescriptorsPerMethod ;
559
+
548
560
// A builder to create one single Set instance for a given set of
549
561
// names or modifiers to reduce the footprint
550
562
// e.g. target modules of qualified exports
551
563
private final DedupSetBuilder dedupSetBuilder
552
564
= new DedupSetBuilder (this ::getNextLocalVar );
553
565
554
566
public SystemModulesClassGenerator (String className ,
555
- List <ModuleInfo > moduleInfos ) {
567
+ List <ModuleInfo > moduleInfos ,
568
+ int moduleDescriptorsPerMethod ) {
556
569
this .classDesc = ClassDesc .ofInternalName (className );
557
570
this .moduleInfos = moduleInfos ;
571
+ this .moduleDescriptorsPerMethod = moduleDescriptorsPerMethod ;
558
572
moduleInfos .forEach (mi -> dedups (mi .descriptor ()));
559
573
}
560
574
@@ -680,25 +694,146 @@ private void genIncubatorModules(ClassBuilder clb) {
680
694
* Generate bytecode for moduleDescriptors method
681
695
*/
682
696
private void genModuleDescriptorsMethod (ClassBuilder clb ) {
697
+ if (moduleInfos .size () <= moduleDescriptorsPerMethod ) {
698
+ clb .withMethodBody (
699
+ "moduleDescriptors" ,
700
+ MTD_ModuleDescriptorArray ,
701
+ ACC_PUBLIC ,
702
+ cob -> {
703
+ cob .constantInstruction (moduleInfos .size ())
704
+ .anewarray (CD_MODULE_DESCRIPTOR )
705
+ .astore (MD_VAR );
706
+
707
+ for (int index = 0 ; index < moduleInfos .size (); index ++) {
708
+ ModuleInfo minfo = moduleInfos .get (index );
709
+ new ModuleDescriptorBuilder (cob ,
710
+ minfo .descriptor (),
711
+ minfo .packages (),
712
+ index ).build ();
713
+ }
714
+ cob .aload (MD_VAR )
715
+ .areturn ();
716
+ });
717
+ return ;
718
+ }
719
+
720
+
721
+ // Split the module descriptors be created by multiple helper methods.
722
+ // Each helper method "subi" creates the maximum N number of module descriptors
723
+ // mi, m{i+1} ...
724
+ // to avoid exceeding the 64kb limit of method length. Then it will call
725
+ // "sub{i+1}" to creates the next batch of module descriptors m{i+n}, m{i+n+1}...
726
+ // and so on. During the construction of the module descriptors, the string sets and
727
+ // modifier sets are deduplicated (see SystemModulesClassGenerator.DedupSetBuilder)
728
+ // and cached in the locals. These locals are saved in an array list so
729
+ // that the helper method can restore the local variables that may be
730
+ // referenced by the bytecode generated for creating module descriptors.
731
+ // Pseudo code looks like this:
732
+ //
733
+ // void subi(ModuleDescriptor[] mdescs, ArrayList<Object> localvars) {
734
+ // // assign localvars to local variables
735
+ // var l3 = localvars.get(0);
736
+ // var l4 = localvars.get(1);
737
+ // :
738
+ // // fill mdescs[i] to mdescs[i+n-1]
739
+ // mdescs[i] = ...
740
+ // mdescs[i+1] = ...
741
+ // :
742
+ // // save new local variables added
743
+ // localvars.add(lx)
744
+ // localvars.add(l{x+1})
745
+ // :
746
+ // sub{i+i}(mdescs, localvars);
747
+ // }
748
+
749
+ List <List <ModuleInfo >> splitModuleInfos = new ArrayList <>();
750
+ List <ModuleInfo > currentModuleInfos = null ;
751
+ for (int index = 0 ; index < moduleInfos .size (); index ++) {
752
+ if (index % moduleDescriptorsPerMethod == 0 ) {
753
+ currentModuleInfos = new ArrayList <>();
754
+ splitModuleInfos .add (currentModuleInfos );
755
+ }
756
+ currentModuleInfos .add (moduleInfos .get (index ));
757
+ }
758
+
759
+ String helperMethodNamePrefix = "sub" ;
760
+ ClassDesc arrayListClassDesc = ClassDesc .ofInternalName ("java/util/ArrayList" );
761
+
683
762
clb .withMethodBody (
684
763
"moduleDescriptors" ,
685
764
MTD_ModuleDescriptorArray ,
686
765
ACC_PUBLIC ,
687
766
cob -> {
688
767
cob .constantInstruction (moduleInfos .size ())
689
768
.anewarray (CD_MODULE_DESCRIPTOR )
769
+ .dup ()
690
770
.astore (MD_VAR );
691
-
692
- for (int index = 0 ; index < moduleInfos .size (); index ++) {
693
- ModuleInfo minfo = moduleInfos .get (index );
694
- new ModuleDescriptorBuilder (cob ,
695
- minfo .descriptor (),
696
- minfo .packages (),
697
- index ).build ();
698
- }
699
- cob .aload (MD_VAR )
771
+ cob .new_ (arrayListClassDesc )
772
+ .dup ()
773
+ .constantInstruction (moduleInfos .size ())
774
+ .invokespecial (arrayListClassDesc , INIT_NAME , MethodTypeDesc .of (CD_void , CD_int ))
775
+ .astore (DEDUP_LIST_VAR );
776
+ cob .aload (0 )
777
+ .aload (MD_VAR )
778
+ .aload (DEDUP_LIST_VAR )
779
+ .invokevirtual (
780
+ this .classDesc ,
781
+ helperMethodNamePrefix + "0" ,
782
+ MethodTypeDesc .of (CD_void , CD_MODULE_DESCRIPTOR .arrayType (), arrayListClassDesc )
783
+ )
700
784
.areturn ();
701
785
});
786
+
787
+ int dedupVarStart = nextLocalVar ;
788
+ for (int n = 0 , count = 0 ; n < splitModuleInfos .size (); count += splitModuleInfos .get (n ).size (), n ++) {
789
+ int index = n ; // the index of which ModuleInfo being processed in the current batch
790
+ int start = count ; // the start index to the return ModuleDescriptor array for the current batch
791
+ int curDedupVar = nextLocalVar ;
792
+ clb .withMethodBody (
793
+ helperMethodNamePrefix + index ,
794
+ MethodTypeDesc .of (CD_void , CD_MODULE_DESCRIPTOR .arrayType (), arrayListClassDesc ),
795
+ ACC_PUBLIC ,
796
+ cob -> {
797
+ if (curDedupVar > dedupVarStart ) {
798
+ for (int i = dedupVarStart ; i < curDedupVar ; i ++) {
799
+ cob .aload (DEDUP_LIST_VAR )
800
+ .constantInstruction (i - dedupVarStart )
801
+ .invokevirtual (arrayListClassDesc , "get" , MethodTypeDesc .of (CD_Object , CD_int ))
802
+ .astore (i );
803
+ }
804
+ }
805
+
806
+ List <ModuleInfo > currentBatch = splitModuleInfos .get (index );
807
+ for (int j = 0 ; j < currentBatch .size (); j ++) {
808
+ ModuleInfo minfo = currentBatch .get (j );
809
+ new ModuleDescriptorBuilder (cob ,
810
+ minfo .descriptor (),
811
+ minfo .packages (),
812
+ start + j ).build ();
813
+ }
814
+
815
+ if (index < splitModuleInfos .size () - 1 ) {
816
+ if (nextLocalVar > curDedupVar ) {
817
+ for (int i = curDedupVar ; i < nextLocalVar ; i ++) {
818
+ cob .aload (DEDUP_LIST_VAR )
819
+ .aload (i )
820
+ .invokevirtual (arrayListClassDesc , "add" , MethodTypeDesc .of (CD_boolean , CD_Object ))
821
+ .pop ();
822
+ }
823
+ }
824
+ cob .aload (0 )
825
+ .aload (MD_VAR )
826
+ .aload (DEDUP_LIST_VAR )
827
+ .invokevirtual (
828
+ this .classDesc ,
829
+ helperMethodNamePrefix + (index +1 ),
830
+ MethodTypeDesc .of (CD_void , CD_MODULE_DESCRIPTOR .arrayType (), arrayListClassDesc )
831
+ );
832
+ }
833
+
834
+ cob .return_ ();
835
+ });
836
+ }
702
837
}
703
838
704
839
/**
0 commit comments