43
43
import com .google .gwt .dev .jjs .impl .FragmentExtractor .CfaLivenessPredicate ;
44
44
import com .google .gwt .dev .jjs .impl .FragmentExtractor .LivenessPredicate ;
45
45
import com .google .gwt .dev .jjs .impl .FragmentExtractor .NothingAlivePredicate ;
46
+ import com .google .gwt .dev .js .JsToStringGenerationVisitor ;
46
47
import com .google .gwt .dev .js .ast .JsBlock ;
47
48
import com .google .gwt .dev .js .ast .JsContext ;
48
49
import com .google .gwt .dev .js .ast .JsModVisitor ;
49
50
import com .google .gwt .dev .js .ast .JsNumericEntry ;
50
51
import com .google .gwt .dev .js .ast .JsProgram ;
51
52
import com .google .gwt .dev .js .ast .JsStatement ;
52
53
import com .google .gwt .dev .util .JsniRef ;
54
+ import com .google .gwt .dev .util .TextOutput ;
53
55
import com .google .gwt .dev .util .collect .HashMap ;
54
56
import com .google .gwt .dev .util .collect .Lists ;
55
57
import com .google .gwt .dev .util .log .speedtracer .CompilerEventType ;
@@ -277,7 +279,10 @@ boolean setLive(String string, int splitPoint) {
277
279
* The property key for a list of initially loaded split points.
278
280
*/
279
281
private static final String PROP_INITIAL_SEQUENCE = "compiler.splitpoint.initial.sequence" ;
280
-
282
+
283
+ public static final String LEFTOVERMERGE_SIZE =
284
+ "compiler.splitpoint.leftovermerge.size" ;
285
+
281
286
public static ControlFlowAnalyzer computeInitiallyLive (JProgram jprogram ) {
282
287
return computeInitiallyLive (jprogram , CodeSplitter .NULL_RECORDER );
283
288
}
@@ -295,16 +300,19 @@ public static ControlFlowAnalyzer computeInitiallyLive(
295
300
return cfa ;
296
301
}
297
302
298
- public static void exec (TreeLogger logger , JProgram jprogram , JsProgram jsprogram ,
303
+ public static void exec (TreeLogger logger , JProgram jprogram ,
304
+ JsProgram jsprogram ,
299
305
JavaToJavaScriptMap map , int fragmentsToMerge ,
300
- MultipleDependencyGraphRecorder dependencyRecorder ) {
306
+ MultipleDependencyGraphRecorder dependencyRecorder ,
307
+ int leftOverMergeLimit ) {
301
308
if (jprogram .getRunAsyncs ().size () == 0 ) {
302
309
// Don't do anything if there is no call to runAsync
303
310
return ;
304
311
}
305
312
Event codeSplitterEvent = SpeedTracerLogger .start (CompilerEventType .CODE_SPLITTER );
306
313
new CodeSplitter2 (
307
- logger , jprogram , jsprogram , map , fragmentsToMerge , dependencyRecorder ).execImpl ();
314
+ logger , jprogram , jsprogram , map , fragmentsToMerge ,
315
+ dependencyRecorder , leftOverMergeLimit ).execImpl ();
308
316
codeSplitterEvent .end ();
309
317
}
310
318
@@ -648,7 +656,8 @@ private static <T> void updateReverseMap(int splitPoint, Map<T, Integer> map, Se
648
656
* Number of split points to merge.
649
657
*/
650
658
private final int splitPointsMerge ;
651
-
659
+ private int leftOverMergeLimit ;
660
+
652
661
/**
653
662
* Maps the split point index X to Y where where that split point X would
654
663
* appear in the Y.cache.js
@@ -665,12 +674,15 @@ private static <T> void updateReverseMap(int splitPoint, Map<T, Integer> map, Se
665
674
*/
666
675
private final int [] splitPointToFragmentMap ;
667
676
668
- private CodeSplitter2 (TreeLogger logger , JProgram jprogram , JsProgram jsprogram ,
677
+ private CodeSplitter2 (TreeLogger logger , JProgram jprogram ,
678
+ JsProgram jsprogram ,
669
679
JavaToJavaScriptMap map , int splitPointsMerge ,
670
- MultipleDependencyGraphRecorder dependencyRecorder ) {
680
+ MultipleDependencyGraphRecorder dependencyRecorder ,
681
+ int leftOverMergeLimit ) {
671
682
this .jprogram = jprogram ;
672
683
this .jsprogram = jsprogram ;
673
684
this .splitPointsMerge = splitPointsMerge ;
685
+ this .leftOverMergeLimit = leftOverMergeLimit ;
674
686
this .fragmentExtractor = new FragmentExtractor (jprogram , jsprogram , map );
675
687
this .initialLoadSequence = new LinkedHashSet <Integer >(jprogram .getSplitPointInitialSequence ());
676
688
@@ -713,7 +725,100 @@ private void addFragment(int splitPoint, LivenessPredicate alreadyLoaded,
713
725
stats .addAll (stmtsToAppend );
714
726
fragmentStats .put (splitPoint , stats );
715
727
}
716
-
728
+
729
+ private boolean fragmentSizeBelowMergeLimit (List <JsStatement > stats ,
730
+ final int leftOverMergeLimit ) {
731
+ int sizeInBytes = 0 ;
732
+ TextOutput out = new TextOutput () {
733
+ int count = 0 ;
734
+
735
+ @ Override
736
+ public int getColumn () {
737
+ return 0 ;
738
+ }
739
+
740
+ @ Override
741
+ public int getLine () {
742
+ return 0 ;
743
+ }
744
+
745
+ @ Override
746
+ public int getPosition () {
747
+ return count ;
748
+ }
749
+
750
+ @ Override
751
+ public void indentIn () {
752
+ }
753
+
754
+ @ Override
755
+ public void indentOut () {
756
+ }
757
+
758
+ @ Override
759
+ public void newline () {
760
+ inc (1 );
761
+ }
762
+
763
+ @ Override
764
+ public void newlineOpt () {
765
+ }
766
+
767
+ @ Override
768
+ public void print (char c ) {
769
+ inc (1 );
770
+ }
771
+
772
+ @ Override
773
+ public void print (char [] s ) {
774
+ inc (s .length );
775
+ }
776
+
777
+ @ Override
778
+ public void print (String s ) {
779
+ inc (s .length ());
780
+ }
781
+
782
+ private void inc (int length ) {
783
+ count += length ;
784
+ if (count >= leftOverMergeLimit ) {
785
+ // yucky, but necessary, early exit
786
+ throw new MergeLimitExceededException ();
787
+ }
788
+ }
789
+
790
+ @ Override
791
+ public void printOpt (char c ) {
792
+ }
793
+
794
+ @ Override
795
+ public void printOpt (char [] s ) {
796
+ }
797
+
798
+ @ Override
799
+ public void printOpt (String s ) {
800
+ }
801
+ };
802
+
803
+ try {
804
+ JsToStringGenerationVisitor v = new JsToStringGenerationVisitor (out );
805
+ for (JsStatement stat : stats ) {
806
+ v .accept (stat );
807
+ }
808
+ sizeInBytes += out .getPosition ();
809
+ } catch (InternalCompilerException me ) {
810
+ if (me .getCause ().getClass () == MergeLimitExceededException .class ) {
811
+ return false ;
812
+ } else {
813
+ throw me ;
814
+ }
815
+ }
816
+ return sizeInBytes < leftOverMergeLimit ;
817
+ }
818
+
819
+ private static class MergeLimitExceededException extends RuntimeException {
820
+ }
821
+
717
822
private ControlFlowAnalyzer computeAllButNCfas (
718
823
ControlFlowAnalyzer liveAfterInitialSequence , List <Integer > sp ) {
719
824
List <ControlFlowAnalyzer > allButOnes = new ArrayList <ControlFlowAnalyzer >();
@@ -867,7 +972,8 @@ private void extractStatements(ControlFlowAnalyzer initiallyLive) {
867
972
}
868
973
}
869
974
allFields .addAll (everything .getFieldsWritten ());
870
-
975
+ ArrayList <JsStatement > leftOverMergeStats = new ArrayList <JsStatement >();
976
+
871
977
// Search for all the atoms that are exclusively needed in each split point.
872
978
for (int i = 1 ; i < splitPointToFragmentMap .length ; i ++) {
873
979
@@ -925,19 +1031,36 @@ private void extractStatements(ControlFlowAnalyzer initiallyLive) {
925
1031
926
1032
LivenessPredicate alreadyLoaded = new ExclusivityMapLivenessPredicate (fragmentMap , 0 );
927
1033
LivenessPredicate liveNow = new ExclusivityMapLivenessPredicate (fragmentMap , i );
928
- List <JsStatement > statsToAppend = fragmentExtractor .createOnLoadedCall (cacheIndex );
929
- addFragment (i , alreadyLoaded , liveNow , statsToAppend , fragmentStats );
1034
+ List <JsStatement > exclusiveStats = fragmentExtractor .extractStatements (liveNow , alreadyLoaded );
1035
+ if (fragmentSizeBelowMergeLimit (exclusiveStats , leftOverMergeLimit )) {
1036
+ leftOverMergeStats .addAll (exclusiveStats );
1037
+ // merged to leftovers
1038
+ splitPointToFragmentMap [i ] = -1 ;
1039
+ continue ;
1040
+ } else {
1041
+ List <JsStatement > statsToAppend = fragmentExtractor .createOnLoadedCall (cacheIndex );
1042
+ addFragment (i , alreadyLoaded , liveNow , statsToAppend , fragmentStats );
1043
+ }
930
1044
cacheIndex ++;
931
1045
}
932
1046
1047
+
1048
+ for (int i = 0 ; i < splitPointToFragmentMap .length ; i ++) {
1049
+ if (splitPointToFragmentMap [i ] == -1 ) {
1050
+ // set fragment number -1 to be leftovers fragment number
1051
+ splitPointToFragmentMap [i ] = splitPointToFragmentMap .length ;
1052
+ }
1053
+ }
1054
+
933
1055
/*
934
1056
* Compute the leftovers fragment.
935
1057
*/
936
1058
{
937
1059
LivenessPredicate alreadyLoaded = new CfaLivenessPredicate (liveAfterInitialSequence );
938
1060
LivenessPredicate liveNow = new ExclusivityMapLivenessPredicate (fragmentMap , 0 );
939
1061
List <JsStatement > statsToAppend = fragmentExtractor .createOnLoadedCall (cacheIndex );
940
- addFragment (splitPointToFragmentMap .length , alreadyLoaded , liveNow , statsToAppend , fragmentStats );
1062
+ leftOverMergeStats .addAll (statsToAppend );
1063
+ addFragment (splitPointToFragmentMap .length , alreadyLoaded , liveNow , leftOverMergeStats , fragmentStats );
941
1064
}
942
1065
943
1066
// now install the new statements in the program fragments
0 commit comments