1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
package cuchaz.enigma.analysis.index;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import cuchaz.enigma.analysis.EntryReference;
import cuchaz.enigma.analysis.ReferenceTargetType;
import cuchaz.enigma.translation.mapping.ResolutionStrategy;
import cuchaz.enigma.translation.representation.Lambda;
import cuchaz.enigma.translation.representation.MethodDescriptor;
import cuchaz.enigma.translation.representation.TypeDescriptor;
import cuchaz.enigma.translation.representation.entry.*;
import java.util.Collection;
import java.util.Map;
public class ReferenceIndex implements JarIndexer {
private Multimap<MethodEntry, MethodEntry> methodReferences = HashMultimap.create();
private Multimap<MethodEntry, EntryReference<MethodEntry, MethodDefEntry>> referencesToMethods = HashMultimap.create();
private Multimap<ClassEntry, EntryReference<ClassEntry, MethodDefEntry>> referencesToClasses = HashMultimap.create();
private Multimap<FieldEntry, EntryReference<FieldEntry, MethodDefEntry>> referencesToFields = HashMultimap.create();
private Multimap<ClassEntry, EntryReference<ClassEntry, FieldDefEntry>> fieldTypeReferences = HashMultimap.create();
private Multimap<ClassEntry, EntryReference<ClassEntry, MethodDefEntry>> methodTypeReferences = HashMultimap.create();
@Override
public void indexMethod(MethodDefEntry methodEntry) {
indexMethodDescriptor(methodEntry, methodEntry.getDesc());
}
private void indexMethodDescriptor(MethodDefEntry entry, MethodDescriptor descriptor) {
for (TypeDescriptor typeDescriptor : descriptor.getArgumentDescs()) {
indexMethodTypeDescriptor(entry, typeDescriptor);
}
indexMethodTypeDescriptor(entry, descriptor.getReturnDesc());
}
private void indexMethodTypeDescriptor(MethodDefEntry method, TypeDescriptor typeDescriptor) {
if (typeDescriptor.isType()) {
ClassEntry referencedClass = typeDescriptor.getTypeEntry();
methodTypeReferences.put(referencedClass, new EntryReference<>(referencedClass, referencedClass.getName(), method));
} else if (typeDescriptor.isArray()) {
indexMethodTypeDescriptor(method, typeDescriptor.getArrayType());
}
}
@Override
public void indexField(FieldDefEntry fieldEntry) {
indexFieldTypeDescriptor(fieldEntry, fieldEntry.getDesc());
}
private void indexFieldTypeDescriptor(FieldDefEntry field, TypeDescriptor typeDescriptor) {
if (typeDescriptor.isType()) {
ClassEntry referencedClass = typeDescriptor.getTypeEntry();
fieldTypeReferences.put(referencedClass, new EntryReference<>(referencedClass, referencedClass.getName(), field));
} else if (typeDescriptor.isArray()) {
indexFieldTypeDescriptor(field, typeDescriptor.getArrayType());
}
}
@Override
public void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry, ReferenceTargetType targetType) {
referencesToMethods.put(referencedEntry, new EntryReference<>(referencedEntry, referencedEntry.getName(), callerEntry, targetType));
methodReferences.put(callerEntry, referencedEntry);
if (referencedEntry.isConstructor()) {
ClassEntry referencedClass = referencedEntry.getParent();
referencesToClasses.put(referencedClass, new EntryReference<>(referencedClass, referencedEntry.getName(), callerEntry, targetType));
}
}
@Override
public void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry, ReferenceTargetType targetType) {
referencesToFields.put(referencedEntry, new EntryReference<>(referencedEntry, referencedEntry.getName(), callerEntry, targetType));
}
@Override
public void indexLambda(MethodDefEntry callerEntry, Lambda lambda, ReferenceTargetType targetType) {
if (lambda.getImplMethod() instanceof MethodEntry) {
indexMethodReference(callerEntry, (MethodEntry) lambda.getImplMethod(), targetType);
} else {
indexFieldReference(callerEntry, (FieldEntry) lambda.getImplMethod(), targetType);
}
indexMethodDescriptor(callerEntry, lambda.getInvokedType());
indexMethodDescriptor(callerEntry, lambda.getSamMethodType());
indexMethodDescriptor(callerEntry, lambda.getInstantiatedMethodType());
}
@Override
public void processIndex(JarIndex index) {
methodReferences = remapReferences(index, methodReferences);
referencesToMethods = remapReferencesTo(index, referencesToMethods);
referencesToClasses = remapReferencesTo(index, referencesToClasses);
referencesToFields = remapReferencesTo(index, referencesToFields);
fieldTypeReferences = remapReferencesTo(index, fieldTypeReferences);
methodTypeReferences = remapReferencesTo(index, methodTypeReferences);
}
private <K extends Entry<?>, V extends Entry<?>> Multimap<K, V> remapReferences(JarIndex index, Multimap<K, V> multimap) {
final int keySetSize = multimap.keySet().size();
Multimap<K, V> resolved = HashMultimap.create(multimap.keySet().size(), keySetSize == 0 ? 0 : multimap.size() / keySetSize);
for (Map.Entry<K, V> entry : multimap.entries()) {
resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue()));
}
return resolved;
}
private <E extends Entry<?>, C extends Entry<?>> Multimap<E, EntryReference<E, C>> remapReferencesTo(JarIndex index, Multimap<E, EntryReference<E, C>> multimap) {
final int keySetSize = multimap.keySet().size();
Multimap<E, EntryReference<E, C>> resolved = HashMultimap.create(keySetSize, keySetSize == 0 ? 0 : multimap.size() / keySetSize);
for (Map.Entry<E, EntryReference<E, C>> entry : multimap.entries()) {
resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue()));
}
return resolved;
}
private <E extends Entry<?>> E remap(JarIndex index, E entry) {
return index.getEntryResolver().resolveFirstEntry(entry, ResolutionStrategy.RESOLVE_CLOSEST);
}
private <E extends Entry<?>, C extends Entry<?>> EntryReference<E, C> remap(JarIndex index, EntryReference<E, C> reference) {
return index.getEntryResolver().resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST);
}
public Collection<MethodEntry> getMethodsReferencedBy(MethodEntry entry) {
return methodReferences.get(entry);
}
public Collection<EntryReference<FieldEntry, MethodDefEntry>> getReferencesToField(FieldEntry entry) {
return referencesToFields.get(entry);
}
public Collection<EntryReference<ClassEntry, MethodDefEntry>> getReferencesToClass(ClassEntry entry) {
return referencesToClasses.get(entry);
}
public Collection<EntryReference<MethodEntry, MethodDefEntry>> getReferencesToMethod(MethodEntry entry) {
return referencesToMethods.get(entry);
}
public Collection<EntryReference<ClassEntry, FieldDefEntry>> getFieldTypeReferencesToClass(ClassEntry entry) {
return fieldTypeReferences.get(entry);
}
public Collection<EntryReference<ClassEntry, MethodDefEntry>> getMethodTypeReferencesToClass(ClassEntry entry) {
return methodTypeReferences.get(entry);
}
}
|