3333import java .util .concurrent .*;
3434import java .util .concurrent .atomic .AtomicReference ;
3535import java .util .function .BiConsumer ;
36+ import java .util .function .Consumer ;
3637import java .util .stream .Collectors ;
3738
3839public class TinyRemapper {
@@ -127,18 +128,28 @@ public Builder skipConflictsChecking(boolean value) {
127128 return this ;
128129 }
129130
131+ public Builder skipPropagate (boolean value ) {
132+ skipPropagate = value ;
133+ return this ;
134+ }
135+
130136 public Builder cacheMappings (boolean value ) {
131137 cacheMappings = value ;
132138 return this ;
133139 }
134140
141+ public Builder logger (Consumer <String > value ) {
142+ logger = value ;
143+ return this ;
144+ }
145+
135146 public TinyRemapper build () {
136147 TinyRemapper remapper = new TinyRemapper (mappingProviders , ignoreFieldDesc , threadCount ,
137148 keepInputData ,
138149 forcePropagation , propagatePrivate ,
139150 removeFrames , ignoreConflicts , resolveMissing , checkPackageAccess || fixPackageAccess , fixPackageAccess ,
140151 rebuildSourceFilenames , skipLocalMapping , renameInvalidLocals , skipConflictsChecking ,
141- cacheMappings , extraAnalyzeVisitor , extraRemapper );
152+ cacheMappings , skipPropagate , extraAnalyzeVisitor , extraRemapper , logger );
142153
143154 return remapper ;
144155 }
@@ -159,8 +170,10 @@ public TinyRemapper build() {
159170 private boolean renameInvalidLocals = false ;
160171 private boolean skipConflictsChecking = false ;
161172 private boolean cacheMappings = false ;
173+ private boolean skipPropagate = false ;
162174 private ClassVisitor extraAnalyzeVisitor ;
163175 private Remapper extraRemapper ;
176+ private Consumer <String > logger = System .out ::println ;
164177 }
165178
166179 private TinyRemapper (Set <IMappingProvider > mappingProviders , boolean ignoreFieldDesc ,
@@ -177,7 +190,10 @@ private TinyRemapper(Set<IMappingProvider> mappingProviders, boolean ignoreField
177190 boolean renameInvalidLocals ,
178191 boolean skipConflictsChecking ,
179192 boolean cacheMappings ,
180- ClassVisitor extraAnalyzeVisitor , Remapper extraRemapper ) {
193+ boolean skipPropagate ,
194+ ClassVisitor extraAnalyzeVisitor ,
195+ Remapper extraRemapper ,
196+ Consumer <String > logger ) {
181197 this .mappingProviders = mappingProviders ;
182198 this .ignoreFieldDesc = ignoreFieldDesc ;
183199 this .threadCount = threadCount > 0 ? threadCount : Math .max (Runtime .getRuntime ().availableProcessors (), 2 );
@@ -195,8 +211,10 @@ private TinyRemapper(Set<IMappingProvider> mappingProviders, boolean ignoreField
195211 this .renameInvalidLocals = renameInvalidLocals ;
196212 this .skipConflictsChecking = skipConflictsChecking ;
197213 this .cacheMappings = cacheMappings ;
214+ this .skipPropagate = skipPropagate ;
198215 this .extraAnalyzeVisitor = extraAnalyzeVisitor ;
199216 this .extraRemapper = extraRemapper ;
217+ this .logger = logger ;
200218 }
201219
202220 public static Builder newRemapper () {
@@ -348,7 +366,7 @@ private CompletableFuture<List<ClassInstance>> read(Path[] inputs, boolean isInp
348366 });
349367 }
350368
351- private static void addClass (ClassInstance cls , Map <String , ClassInstance > out ) {
369+ private void addClass (ClassInstance cls , Map <String , ClassInstance > out ) {
352370 String name = cls .getName ();
353371
354372 // add new class or replace non-input class with input class, warn if two input classes clash
@@ -358,7 +376,7 @@ private static void addClass(ClassInstance cls, Map<String, ClassInstance> out)
358376
359377 if (cls .isInput ) {
360378 if (prev .isInput ) {
361- System . out . printf ("duplicate input class %s, from %s and %s%n " , name , prev .srcPath , cls .srcPath );
379+ logger . accept ( String . format ("duplicate input class %s, from %s and %s" , name , prev .srcPath , cls .srcPath ) );
362380 prev .addInputTags (cls .getInputTags ());
363381 return ;
364382 } else if (out .replace (name , prev , cls )) { // cas with retry-loop on failure
@@ -368,6 +386,11 @@ private static void addClass(ClassInstance cls, Map<String, ClassInstance> out)
368386 // loop
369387 }
370388 } else {
389+ if (out == readClasses ) {
390+ mergedClasspath = false ;
391+ mappingsDirty = true ;
392+ }
393+
371394 prev .addInputTags (cls .getInputTags ());
372395 return ;
373396 }
@@ -385,7 +408,7 @@ private CompletableFuture<List<ClassInstance>> read(Path file, boolean isInput,
385408 ClassInstance res = analyze (isInput , tags , srcPath , Files .readAllBytes (file ));
386409 if (res != null ) return Collections .singletonList (res );
387410 } catch (IOException e ) {
388- System . out . println (file .toAbsolutePath ());
411+ logger . accept (file .toAbsolutePath (). toString ());
389412 e .printStackTrace ();
390413 }
391414 return Collections .emptyList ();
@@ -414,7 +437,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
414437 } catch (URISyntaxException e ) {
415438 throw new RuntimeException (e );
416439 } catch (IOException e ) {
417- System . out . println (file .toAbsolutePath ());
440+ logger . accept (file .toAbsolutePath (). toString ());
418441 e .printStackTrace ();
419442 }
420443 }
@@ -461,20 +484,16 @@ String mapClass(String className) {
461484 }
462485
463486 private void loadMappings (boolean ignoreCached ) {
464- if (ignoreCached ) {
487+ if (mappingsDirty || ignoreCached ) {
465488 classMap .clear ();
466489 methodMap .clear ();
467490 methodArgMap .clear ();
468491 fieldMap .clear ();
469-
470- for (ClassInstance node : classes .values ()) {
471- node .parents .clear ();
472- node .children .clear ();
473- }
492+ unmergeClasses ();
474493
475494 mappingsDirty = true ;
476495 }
477-
496+
478497 if (!mappingsDirty ) return ;
479498 mappingsDirty = false ;
480499 MappingAcceptor acceptor = new MappingAcceptor () {
@@ -537,8 +556,6 @@ public void acceptField(Member field, String dstName) {
537556 }
538557
539558 checkClassMappings ();
540- mergeClasspath ();
541- propagate ();
542559 }
543560
544561 public void replaceMappings (Set <IMappingProvider > providers ) {
@@ -569,35 +586,47 @@ private void checkClassMappings() {
569586 duplicates .add (name );
570587 }
571588 }
572-
573- System . out . println ("non-unique class target name mappings:" );
589+
590+ logger . accept ("non-unique class target name mappings:" );
574591
575592 for (String target : duplicates ) {
576- System .out .print (" [" );
593+ StringBuilder builder = new StringBuilder ();
594+ builder .append (" [" );
577595 boolean first = true ;
578596
579597 for (Map .Entry <String , String > e : classMap .entrySet ()) {
580598 if (e .getValue ().equals (target )) {
581599 if (first ) {
582600 first = false ;
583601 } else {
584- System . out . print (", " );
602+ builder . append (", " );
585603 }
586-
587- System . out . print (e .getKey ());
604+
605+ builder . append (e .getKey ());
588606 }
589607 }
590-
591- System .out .printf ("] -> %s%n" , target );
608+
609+ builder .append ("] -> " ).append (target );
610+ logger .accept (builder .toString ());
592611 }
593612
594613 throw new RuntimeException ("duplicate class target name mappings detected" );
595614 }
596615 }
616+
617+ private void unmergeClasses () {
618+ mergedClasspath = false ;
619+ for (ClassInstance node : classes .values ()) {
620+ node .parents .clear ();
621+ node .children .clear ();
622+ }
623+ }
597624
598625 private void mergeClasspath () {
626+ if (mergedClasspath ) return ;
627+ mergedClasspath = true ;
599628 for (ClassInstance node : classes .values ()) {
600- if (node .isInput ) return ;
629+ if (node .isInput ) continue ;
601630 assert node .getSuperName () != null ;
602631
603632 ClassInstance parent = classes .get (node .getSuperName ());
@@ -619,8 +648,9 @@ private void mergeClasspath() {
619648 }
620649
621650 private void mergeInput () {
622- for (ClassInstance node : classes .values ()) {
623- if (!node .isInput ) return ;
651+ for (ClassInstance node : classes .values ().parallelStream ()
652+ .filter (node -> node .isInput )
653+ .collect (Collectors .toList ())) {
624654 assert node .getSuperName () != null ;
625655
626656 ClassInstance parent = classes .get (node .getSuperName ());
@@ -650,6 +680,16 @@ private void unmergeInput() {
650680 }
651681
652682 private void propagate () {
683+ if (skipPropagate ) return ;
684+ conflicts .clear ();
685+ classes .values ().parallelStream ().forEach (value -> {
686+ value .resolvedMembers = new ConcurrentHashMap <>();
687+ for (MemberInstance member : value .getMembers ()) {
688+ member .forceSetNewName (null );
689+ member .newNameOriginatingCls = null ;
690+ }
691+ });
692+
653693 List <Future <?>> futures = new ArrayList <>();
654694 List <Map .Entry <String , String >> tasks = new ArrayList <>();
655695 int maxTasks = methodMap .size () / threadCount / 4 ;
@@ -699,7 +739,7 @@ private void handleConflicts() {
699739 if (testSet .size () != cls .getMembers ().size ()) {
700740 if (!targetNameCheckFailed ) {
701741 targetNameCheckFailed = true ;
702- System . out . println ("Mapping target name conflicts detected:" );
742+ logger . accept ("Mapping target name conflicts detected:" );
703743 }
704744
705745 Map <String , List <MemberInstance >> duplicates = new HashMap <>();
@@ -717,22 +757,25 @@ private void handleConflicts() {
717757 if (members .size () < 2 ) continue ;
718758
719759 MemberInstance anyMember = members .get (0 );
720- System .out .printf (" %ss %s/[" , anyMember .type , cls .getName ());
760+ StringBuilder builder = new StringBuilder ();
761+ builder .append (" " ).append (anyMember .type ).append ("s " ).append (cls .getName ()).append ("/[" );
721762
722763 for (int i = 0 ; i < members .size (); i ++) {
723- if (i != 0 ) System . out . print (", " );
764+ if (i != 0 ) builder . append (", " );
724765
725766 MemberInstance member = members .get (i );
726767
727768 if (member .newNameOriginatingCls != null && !member .newNameOriginatingCls .equals (cls .getName ())) {
728- System . out . print (member .newNameOriginatingCls );
729- System . out . print ('/' );
769+ builder . append (member .newNameOriginatingCls );
770+ builder . append ('/' );
730771 }
731-
732- System . out . print (member .name );
772+
773+ builder . append (member .name );
733774 }
734-
735- System .out .printf ("]%s -> %s%n" , MemberInstance .getId (anyMember .type , "" , anyMember .desc , ignoreFieldDesc ), MemberInstance .getNameFromId (anyMember .type , nameDesc , ignoreFieldDesc ));
775+
776+ builder .append (']' ).append (MemberInstance .getId (anyMember .type , "" , anyMember .desc , ignoreFieldDesc ));
777+ builder .append (" -> " ).append (MemberInstance .getNameFromId (anyMember .type , nameDesc , ignoreFieldDesc ));
778+ logger .accept (builder .toString ());
736779 }
737780 }
738781
@@ -742,15 +785,15 @@ private void handleConflicts() {
742785 boolean unfixableConflicts = false ;
743786
744787 if (!conflicts .isEmpty ()) {
745- System . out . println ("Mapping source name conflicts detected:" );
788+ logger . accept ("Mapping source name conflicts detected:" );
746789
747790 for (Map .Entry <MemberInstance , Set <String >> entry : conflicts .entrySet ()) {
748791 MemberInstance member = entry .getKey ();
749792 String newName = member .getNewName ();
750793 Set <String > names = entry .getValue ();
751794 names .add (member .cls .getName ()+"/" +newName );
752795
753- System . out . printf (" %s %s %s (%s) -> %s%n " , member .cls .getName (), member .type .name (), member .name , member .desc , names );
796+ logger . accept ( String . format (" %s %s %s (%s) -> %s" , member .cls .getName (), member .type .name (), member .name , member .desc , names ) );
754797
755798 if (ignoreConflicts ) {
756799 Map <String , String > mappings = member .type == MemberType .METHOD ? methodMap : fieldMap ;
@@ -772,14 +815,14 @@ private void handleConflicts() {
772815 unfixableConflicts = true ;
773816 } else {
774817 member .forceSetNewName (mappingName );
775- System . out . println (" fixable: replaced with " +mappingName );
818+ logger . accept (" fixable: replaced with " +mappingName );
776819 }
777820 }
778821 }
779822 }
780823
781824 if (!conflicts .isEmpty () && !ignoreConflicts || unfixableConflicts || targetNameCheckFailed ) {
782- if (ignoreConflicts || targetNameCheckFailed ) System . out . println ("There were unfixable conflicts." );
825+ if (ignoreConflicts || targetNameCheckFailed ) logger . accept ("There were unfixable conflicts." );
783826
784827 System .exit (1 );
785828 }
@@ -828,7 +871,7 @@ public void apply(final BiConsumer<String, byte[]> outputConsumer, InputTag... i
828871
829872 if (fixPackageAccess ) {
830873 if (needsFixes ) {
831- System . out . printf ("Fixing access for %d classes and %d members.%n " , classesToMakePublic .size (), membersToMakePublic .size ());
874+ logger . accept ( String . format ("Fixing access for %d classes and %d members." , classesToMakePublic .size (), membersToMakePublic .size () ));
832875 }
833876
834877 for (Map .Entry <ClassInstance , byte []> entry : outputBuffer .entrySet ()) {
@@ -912,7 +955,9 @@ private void refresh() {
912955
913956 _prepareClasses ();
914957 loadMappings (!cacheMappings );
958+ mergeClasspath ();
915959 mergeInput ();
960+ propagate ();
916961
917962 assert dirty ;
918963 dirty = false ;
@@ -1122,8 +1167,10 @@ public boolean isMappingsDirty() {
11221167 private final boolean renameInvalidLocals ;
11231168 private final boolean skipConflictsChecking ;
11241169 private final boolean cacheMappings ;
1170+ private final boolean skipPropagate ;
11251171 private final ClassVisitor extraAnalyzeVisitor ;
11261172 final Remapper extraRemapper ;
1173+ final Consumer <String > logger ;
11271174
11281175 final AtomicReference <Map <InputTag , InputTag []>> singleInputTags = new AtomicReference <>(Collections .emptyMap ()); // cache for tag -> { tag }
11291176
@@ -1144,6 +1191,7 @@ public boolean isMappingsDirty() {
11441191 private final ExecutorService threadPool ;
11451192 private final AsmRemapper remapper = new AsmRemapper (this );
11461193
1194+ private boolean mergedClasspath = false ;
11471195 private boolean mappingsDirty = true ;
11481196 private volatile boolean dirty = true ; // volatile to make the state debug asserts more reliable, shouldn't actually see concurrent modifications
11491197 private Map <ClassInstance , byte []> outputBuffer ;
0 commit comments