1
1
package dev .su5ed .sinytra .connector .transformer ;
2
2
3
+ import dev .su5ed .sinytra .adapter .patch .selector .AnnotationHandle ;
3
4
import dev .su5ed .sinytra .adapter .patch .util .MethodQualifier ;
4
5
import net .minecraftforge .fart .api .ClassProvider ;
5
6
import net .minecraftforge .fart .api .Transformer ;
13
14
import org .objectweb .asm .ClassReader ;
14
15
import org .objectweb .asm .ClassVisitor ;
15
16
import org .objectweb .asm .ClassWriter ;
17
+ import org .objectweb .asm .Handle ;
16
18
import org .objectweb .asm .Opcodes ;
17
19
import org .objectweb .asm .Type ;
18
20
import org .objectweb .asm .commons .ClassRemapper ;
21
+ import org .objectweb .asm .commons .Remapper ;
22
+ import org .objectweb .asm .tree .AbstractInsnNode ;
23
+ import org .objectweb .asm .tree .AnnotationNode ;
24
+ import org .objectweb .asm .tree .ClassNode ;
25
+ import org .objectweb .asm .tree .FieldNode ;
26
+ import org .objectweb .asm .tree .InvokeDynamicInsnNode ;
27
+ import org .objectweb .asm .tree .LdcInsnNode ;
28
+ import org .objectweb .asm .tree .MethodNode ;
19
29
20
30
import java .io .IOException ;
21
31
import java .util .Collection ;
22
32
import java .util .HashSet ;
33
+ import java .util .List ;
23
34
import java .util .Map ;
24
35
import java .util .Optional ;
25
36
import java .util .Set ;
26
37
import java .util .concurrent .ConcurrentHashMap ;
27
38
import java .util .function .Consumer ;
39
+ import java .util .function .UnaryOperator ;
28
40
import java .util .stream .Stream ;
29
41
30
42
public final class OptimizedRenamingTransformer extends RenamingTransformer {
31
43
private static final String CLASS_DESC_PATTERN = "^L[a-zA-Z0-9/$_]+;$" ;
44
+ private static final String FQN_CLASS_NAME_PATTERN = "^([a-zA-Z0-9$_]+\\ .)*[a-zA-Z0-9$_]+$" ;
32
45
33
46
public static Transformer create (ClassProvider classProvider , Consumer <String > log , IMappingFile mappingFile , Map <String , String > flatMappings ) {
34
47
RenamingClassProvider reverseProvider = new RenamingClassProvider (classProvider , mappingFile , mappingFile .reverse (), log );
@@ -40,6 +53,100 @@ public OptimizedRenamingTransformer(EnhancedRemapper remapper, boolean collectAb
40
53
super (remapper , collectAbstractParams );
41
54
}
42
55
56
+ @ Override
57
+ protected void postProcess (ClassNode node ) {
58
+ super .postProcess (node );
59
+
60
+ // Remap raw values (usually found in reflection calls) and unmapped mixin annotations
61
+ // This is done in a "post-processing" phase rather than inside the main remapper's mapValue method
62
+ // so that we're able to determine the "remap" mixin annotation value ahead of time, and only remap it when necessary
63
+ PostProcessRemapper postProcessRemapper = new PostProcessRemapper (((RelocatingEnhancedRemapper ) this .remapper ).flatMappings , this .remapper );
64
+ for (MethodNode method : node .methods ) {
65
+ if (method .visibleAnnotations != null ) {
66
+ // If remap has been set to false during compilation, we must manually map the annotation values ourselves instead of relying on the provided refmap
67
+ if (method .visibleAnnotations .stream ().anyMatch (ann -> new AnnotationHandle (ann ).<Boolean >getValue ("remap" ).map (h -> !h .get ()).orElse (false ))) {
68
+ for (AnnotationNode annotation : method .visibleAnnotations ) {
69
+ postProcessRemapper .mapAnnotationValues (annotation .values );
70
+ }
71
+ }
72
+ }
73
+ for (AbstractInsnNode insn : method .instructions ) {
74
+ if (insn instanceof LdcInsnNode ldc ) {
75
+ ldc .cst = postProcessRemapper .mapValue (ldc .cst );
76
+ }
77
+ if (insn instanceof InvokeDynamicInsnNode indy ) {
78
+ for (int i = 0 ; i < indy .bsmArgs .length ; i ++) {
79
+ indy .bsmArgs [i ] = postProcessRemapper .mapValue (indy .bsmArgs [i ]);
80
+ indy .bsm = (Handle ) postProcessRemapper .mapValue (indy .bsm );
81
+ }
82
+ }
83
+ }
84
+ }
85
+ for (FieldNode field : node .fields ) {
86
+ field .value = postProcessRemapper .mapValue (field .value );
87
+ }
88
+ }
89
+
90
+ private static class PostProcessRemapper {
91
+ private final Map <String , String > flatMappings ;
92
+ private final Remapper remapper ;
93
+
94
+ public PostProcessRemapper (Map <String , String > flatMappings , Remapper remapper ) {
95
+ this .flatMappings = flatMappings ;
96
+ this .remapper = remapper ;
97
+ }
98
+
99
+ public void mapAnnotationValues (List <Object > values ) {
100
+ for (int i = 1 ; i < values .size (); i += 2 ) {
101
+ values .set (i , mapAnnotationValue (values .get (i )));
102
+ }
103
+ }
104
+
105
+ public Object mapAnnotationValue (Object obj ) {
106
+ if (obj instanceof AnnotationNode annotation ) {
107
+ mapAnnotationValues (annotation .values );
108
+ }
109
+ else if (obj instanceof List list ) {
110
+ list .replaceAll (this ::mapAnnotationValue );
111
+ }
112
+ else {
113
+ return mapValue (obj );
114
+ }
115
+ return obj ;
116
+ }
117
+
118
+ public Object mapValue (Object value ) {
119
+ if (value instanceof String str ) {
120
+ if (str .matches (CLASS_DESC_PATTERN )) {
121
+ String mapped = flatMappings .get (str .substring (1 , str .length () - 1 ));
122
+ if (mapped != null ) {
123
+ return 'L' + mapped + ';' ;
124
+ }
125
+ }
126
+ else if (str .matches (FQN_CLASS_NAME_PATTERN )) {
127
+ String mapped = flatMappings .get (str .replace ('.' , '/' ));
128
+ if (mapped != null ) {
129
+ return mapped .replace ('/' , '.' );
130
+ }
131
+ }
132
+
133
+ MethodQualifier qualifier = MethodQualifier .create (str ).orElse (null );
134
+ if (qualifier != null && qualifier .desc () != null ) {
135
+ String owner = qualifier .owner () != null ? this .remapper .mapDesc (qualifier .owner ()) : "" ;
136
+ String name = qualifier .name () != null ? this .flatMappings .getOrDefault (qualifier .name (), qualifier .name ()) : "" ;
137
+ String desc = qualifier .desc () != null ? this .remapper .mapMethodDesc (qualifier .desc ()) : "" ;
138
+ return owner + name + desc ;
139
+ }
140
+
141
+ String mapped = this .flatMappings .get (str );
142
+ if (mapped != null ) {
143
+ return mapped ;
144
+ }
145
+ }
146
+ return this .remapper .mapValue (value );
147
+ }
148
+ }
149
+
43
150
private static final class RenamingClassProvider implements ClassProvider {
44
151
private final ClassProvider upstream ;
45
152
private final IMappingFile forwardMapping ;
@@ -85,44 +192,6 @@ public void close() throws IOException {
85
192
}
86
193
}
87
194
88
- private static class MixinTargetAnalyzer extends ClassVisitor {
89
- private final Set <String > targets = new HashSet <>();
90
-
91
- public MixinTargetAnalyzer (int api , ClassVisitor classVisitor ) {
92
- super (api , classVisitor );
93
- }
94
-
95
- @ Override
96
- public AnnotationVisitor visitAnnotation (String descriptor , boolean visible ) {
97
- return new MixinAnnotationVisitor (this .api , super .visitAnnotation (descriptor , visible ), this .targets , null );
98
- }
99
- }
100
-
101
- private static class MixinAnnotationVisitor extends AnnotationVisitor {
102
- private final Set <String > targets ;
103
- private final String attributeName ;
104
-
105
- public MixinAnnotationVisitor (int api , AnnotationVisitor annotationVisitor , Set <String > targets , String attributeName ) {
106
- super (api , annotationVisitor );
107
-
108
- this .targets = targets ;
109
- this .attributeName = attributeName ;
110
- }
111
-
112
- @ Override
113
- public void visit (String name , Object value ) {
114
- super .visit (name , value );
115
- if ("value" .equals (this .attributeName ) && value instanceof Type type ) {
116
- this .targets .add (type .getInternalName ());
117
- }
118
- }
119
-
120
- @ Override
121
- public AnnotationVisitor visitArray (String name ) {
122
- return new MixinAnnotationVisitor (this .api , super .visitArray (name ), this .targets , name );
123
- }
124
- }
125
-
126
195
private static class RelocatingEnhancedRemapper extends EnhancedRemapper {
127
196
private final Map <String , String > flatMappings ;
128
197
@@ -185,32 +254,43 @@ public String mapPackageName(String name) {
185
254
// We don't need to map these
186
255
return name ;
187
256
}
257
+ }
258
+
259
+ private static class MixinTargetAnalyzer extends ClassVisitor {
260
+ private final Set <String > targets = new HashSet <>();
261
+
262
+ public MixinTargetAnalyzer (int api , ClassVisitor classVisitor ) {
263
+ super (api , classVisitor );
264
+ }
188
265
189
- // An attempt at remapping reflection calls and mixin method names
190
266
@ Override
191
- public Object mapValue (Object value ) {
192
- if (value instanceof String str ) {
193
- if (str .matches (CLASS_DESC_PATTERN )) {
194
- String mapped = this .flatMappings .get (str .substring (1 , str .length () - 1 ));
195
- if (mapped != null ) {
196
- return 'L' + mapped + ';' ;
197
- }
198
- }
267
+ public AnnotationVisitor visitAnnotation (String descriptor , boolean visible ) {
268
+ return new MixinAnnotationVisitor (this .api , super .visitAnnotation (descriptor , visible ), this .targets , null );
269
+ }
270
+ }
199
271
200
- MethodQualifier qualifier = MethodQualifier .create (str ).orElse (null );
201
- if (qualifier != null && qualifier .desc () != null ) {
202
- String owner = qualifier .owner () != null ? mapDesc (qualifier .owner ()) : "" ;
203
- String name = qualifier .name () != null ? this .flatMappings .getOrDefault (qualifier .name (), qualifier .name ()) : "" ;
204
- String desc = qualifier .desc () != null ? mapMethodDesc (qualifier .desc ()) : "" ;
205
- return owner + name + desc ;
206
- }
272
+ private static class MixinAnnotationVisitor extends AnnotationVisitor {
273
+ private final Set <String > targets ;
274
+ private final String attributeName ;
207
275
208
- String mapped = this .flatMappings .get (str );
209
- if (mapped != null ) {
210
- return mapped ;
211
- }
276
+ public MixinAnnotationVisitor (int api , AnnotationVisitor annotationVisitor , Set <String > targets , String attributeName ) {
277
+ super (api , annotationVisitor );
278
+
279
+ this .targets = targets ;
280
+ this .attributeName = attributeName ;
281
+ }
282
+
283
+ @ Override
284
+ public void visit (String name , Object value ) {
285
+ super .visit (name , value );
286
+ if ("value" .equals (this .attributeName ) && value instanceof Type type ) {
287
+ this .targets .add (type .getInternalName ());
212
288
}
213
- return super .mapValue (value );
289
+ }
290
+
291
+ @ Override
292
+ public AnnotationVisitor visitArray (String name ) {
293
+ return new MixinAnnotationVisitor (this .api , super .visitArray (name ), this .targets , name );
214
294
}
215
295
}
216
296
0 commit comments