diff options
| author | 2019-05-10 22:21:11 +0200 | |
|---|---|---|
| committer | 2019-05-10 22:21:11 +0200 | |
| commit | 75f383a1956eb19fc838ea647a7e7b24552324cf (patch) | |
| tree | d0aa11a90110b60404f40a5f7f39704598491585 /src/main/java/cuchaz/enigma/analysis/index | |
| parent | Use our procyon to fix compiler issues (#128) (diff) | |
| download | enigma-fork-75f383a1956eb19fc838ea647a7e7b24552324cf.tar.gz enigma-fork-75f383a1956eb19fc838ea647a7e7b24552324cf.tar.xz enigma-fork-75f383a1956eb19fc838ea647a7e7b24552324cf.zip | |
Don't remap specialized methods to their bridge partner in bytecode
Diffstat (limited to 'src/main/java/cuchaz/enigma/analysis/index')
3 files changed, 33 insertions, 65 deletions
diff --git a/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java b/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java index 649ce25..8a9b459 100644 --- a/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java | |||
| @@ -17,8 +17,8 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 17 | private final InheritanceIndex inheritanceIndex; | 17 | private final InheritanceIndex inheritanceIndex; |
| 18 | private final ReferenceIndex referenceIndex; | 18 | private final ReferenceIndex referenceIndex; |
| 19 | 19 | ||
| 20 | private final Set<MethodEntry> bridgeMethods = Sets.newHashSet(); | 20 | private final Set<MethodEntry> bridgeToSpecialized = Sets.newHashSet(); |
| 21 | private final Map<MethodEntry, MethodEntry> accessedToBridge = Maps.newHashMap(); | 21 | private final Map<MethodEntry, MethodEntry> specializedToBridge = Maps.newHashMap(); |
| 22 | 22 | ||
| 23 | public BridgeMethodIndex(EntryIndex entryIndex, InheritanceIndex inheritanceIndex, ReferenceIndex referenceIndex) { | 23 | public BridgeMethodIndex(EntryIndex entryIndex, InheritanceIndex inheritanceIndex, ReferenceIndex referenceIndex) { |
| 24 | this.entryIndex = entryIndex; | 24 | this.entryIndex = entryIndex; |
| @@ -42,34 +42,34 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 42 | 42 | ||
| 43 | @Override | 43 | @Override |
| 44 | public void processIndex(JarIndex index) { | 44 | public void processIndex(JarIndex index) { |
| 45 | Map<MethodEntry, MethodEntry> copiedAccessToBridge = new HashMap<>(accessedToBridge); | 45 | Map<MethodEntry, MethodEntry> copiedAccessToBridge = new HashMap<>(specializedToBridge); |
| 46 | 46 | ||
| 47 | for (Map.Entry<MethodEntry, MethodEntry> entry : copiedAccessToBridge.entrySet()) { | 47 | for (Map.Entry<MethodEntry, MethodEntry> entry : copiedAccessToBridge.entrySet()) { |
| 48 | MethodEntry accessedEntry = entry.getKey(); | 48 | MethodEntry specializedEntry = entry.getKey(); |
| 49 | MethodEntry bridgeEntry = entry.getValue(); | 49 | MethodEntry bridgeEntry = entry.getValue(); |
| 50 | if (bridgeEntry.getName().equals(accessedEntry.getName())) { | 50 | if (bridgeEntry.getName().equals(specializedEntry.getName())) { |
| 51 | continue; | 51 | continue; |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | MethodEntry renamedAccessedEntry = accessedEntry.withName(bridgeEntry.getName()); | 54 | MethodEntry renamedSpecializedEntry = specializedEntry.withName(bridgeEntry.getName()); |
| 55 | bridgeMethods.add(renamedAccessedEntry); | 55 | bridgeToSpecialized.add(renamedSpecializedEntry); |
| 56 | accessedToBridge.put(renamedAccessedEntry, accessedToBridge.get(accessedEntry)); | 56 | specializedToBridge.put(renamedSpecializedEntry, specializedToBridge.get(specializedEntry)); |
| 57 | } | 57 | } |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | private void indexSyntheticMethod(MethodDefEntry syntheticMethod, AccessFlags access) { | 60 | private void indexSyntheticMethod(MethodDefEntry syntheticMethod, AccessFlags access) { |
| 61 | MethodEntry accessedMethod = findAccessMethod(syntheticMethod); | 61 | MethodEntry specializedMethod = findSpecializedMethod(syntheticMethod); |
| 62 | if (accessedMethod == null) { | 62 | if (specializedMethod == null) { |
| 63 | return; | 63 | return; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | if (access.isBridge() || isPotentialBridge(syntheticMethod, accessedMethod)) { | 66 | if (access.isBridge() || isPotentialBridge(syntheticMethod, specializedMethod)) { |
| 67 | bridgeMethods.add(syntheticMethod); | 67 | bridgeToSpecialized.add(syntheticMethod); |
| 68 | accessedToBridge.put(accessedMethod, syntheticMethod); | 68 | specializedToBridge.put(specializedMethod, syntheticMethod); |
| 69 | } | 69 | } |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | private MethodEntry findAccessMethod(MethodEntry method) { | 72 | private MethodEntry findSpecializedMethod(MethodEntry method) { |
| 73 | // we want to find all compiler-added methods that directly call another with no processing | 73 | // we want to find all compiler-added methods that directly call another with no processing |
| 74 | 74 | ||
| 75 | // get all the methods that we call | 75 | // get all the methods that we call |
| @@ -83,7 +83,7 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 83 | return referencedMethods.stream().findFirst().orElse(null); | 83 | return referencedMethods.stream().findFirst().orElse(null); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | private boolean isPotentialBridge(MethodDefEntry bridgeMethod, MethodEntry accessedMethod) { | 86 | private boolean isPotentialBridge(MethodDefEntry bridgeMethod, MethodEntry specializedMethod) { |
| 87 | // Bridge methods only exist for inheritance purposes, if we're private, final, or static, we cannot be inherited | 87 | // Bridge methods only exist for inheritance purposes, if we're private, final, or static, we cannot be inherited |
| 88 | AccessFlags bridgeAccess = bridgeMethod.getAccess(); | 88 | AccessFlags bridgeAccess = bridgeMethod.getAccess(); |
| 89 | if (bridgeAccess.isPrivate() || bridgeAccess.isFinal() || bridgeAccess.isStatic()) { | 89 | if (bridgeAccess.isPrivate() || bridgeAccess.isFinal() || bridgeAccess.isStatic()) { |
| @@ -91,35 +91,35 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | MethodDescriptor bridgeDesc = bridgeMethod.getDesc(); | 93 | MethodDescriptor bridgeDesc = bridgeMethod.getDesc(); |
| 94 | MethodDescriptor accessedDesc = accessedMethod.getDesc(); | 94 | MethodDescriptor specializedDesc = specializedMethod.getDesc(); |
| 95 | List<TypeDescriptor> bridgeArguments = bridgeDesc.getArgumentDescs(); | 95 | List<TypeDescriptor> bridgeArguments = bridgeDesc.getArgumentDescs(); |
| 96 | List<TypeDescriptor> accessedArguments = accessedDesc.getArgumentDescs(); | 96 | List<TypeDescriptor> specializedArguments = specializedDesc.getArgumentDescs(); |
| 97 | 97 | ||
| 98 | // A bridge method will always have the same number of arguments | 98 | // A bridge method will always have the same number of arguments |
| 99 | if (bridgeArguments.size() != accessedArguments.size()) { | 99 | if (bridgeArguments.size() != specializedArguments.size()) { |
| 100 | return false; | 100 | return false; |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | // Check that all argument types are bridge-compatible | 103 | // Check that all argument types are bridge-compatible |
| 104 | for (int i = 0; i < bridgeArguments.size(); i++) { | 104 | for (int i = 0; i < bridgeArguments.size(); i++) { |
| 105 | if (!areTypesBridgeCompatible(bridgeArguments.get(i), accessedArguments.get(i))) { | 105 | if (!areTypesBridgeCompatible(bridgeArguments.get(i), specializedArguments.get(i))) { |
| 106 | return false; | 106 | return false; |
| 107 | } | 107 | } |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | // Check that the return type is bridge-compatible | 110 | // Check that the return type is bridge-compatible |
| 111 | return areTypesBridgeCompatible(bridgeDesc.getReturnDesc(), accessedDesc.getReturnDesc()); | 111 | return areTypesBridgeCompatible(bridgeDesc.getReturnDesc(), specializedDesc.getReturnDesc()); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | private boolean areTypesBridgeCompatible(TypeDescriptor bridgeDesc, TypeDescriptor accessedDesc) { | 114 | private boolean areTypesBridgeCompatible(TypeDescriptor bridgeDesc, TypeDescriptor specializedDesc) { |
| 115 | if (bridgeDesc.equals(accessedDesc)) { | 115 | if (bridgeDesc.equals(specializedDesc)) { |
| 116 | return true; | 116 | return true; |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | // Either the descs will be equal, or they are both types and different through a generic | 119 | // Either the descs will be equal, or they are both types and different through a generic |
| 120 | if (bridgeDesc.isType() && accessedDesc.isType()) { | 120 | if (bridgeDesc.isType() && specializedDesc.isType()) { |
| 121 | ClassEntry bridgeType = bridgeDesc.getTypeEntry(); | 121 | ClassEntry bridgeType = bridgeDesc.getTypeEntry(); |
| 122 | ClassEntry accessedType = accessedDesc.getTypeEntry(); | 122 | ClassEntry accessedType = specializedDesc.getTypeEntry(); |
| 123 | 123 | ||
| 124 | // If the given types are completely unrelated to each other, this can't be bridge compatible | 124 | // If the given types are completely unrelated to each other, this can't be bridge compatible |
| 125 | InheritanceIndex.Relation relation = inheritanceIndex.computeClassRelation(accessedType, bridgeType); | 125 | InheritanceIndex.Relation relation = inheritanceIndex.computeClassRelation(accessedType, bridgeType); |
| @@ -130,19 +130,19 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | public boolean isBridgeMethod(MethodEntry entry) { | 132 | public boolean isBridgeMethod(MethodEntry entry) { |
| 133 | return bridgeMethods.contains(entry); | 133 | return bridgeToSpecialized.contains(entry); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | public boolean isAccessedByBridge(MethodEntry entry) { | 136 | public boolean isSpecializedMethod(MethodEntry entry) { |
| 137 | return accessedToBridge.containsKey(entry); | 137 | return specializedToBridge.containsKey(entry); |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | @Nullable | 140 | @Nullable |
| 141 | public MethodEntry getBridgeFromAccessed(MethodEntry entry) { | 141 | public MethodEntry getBridgeFromSpecialized(MethodEntry specialized) { |
| 142 | return accessedToBridge.get(entry); | 142 | return specializedToBridge.get(specialized); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | public Map<MethodEntry, MethodEntry> getAccessedToBridge() { | 145 | public Map<MethodEntry, MethodEntry> getSpecializedToBridge() { |
| 146 | return Collections.unmodifiableMap(accessedToBridge); | 146 | return Collections.unmodifiableMap(specializedToBridge); |
| 147 | } | 147 | } |
| 148 | } | 148 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java b/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java index 645110a..773eaf1 100644 --- a/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java | |||
| @@ -28,18 +28,6 @@ public class EntryIndex implements JarIndexer { | |||
| 28 | fields.put(fieldEntry, fieldEntry.getAccess()); | 28 | fields.put(fieldEntry, fieldEntry.getAccess()); |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | @Override | ||
| 32 | public void processIndex(JarIndex index) { | ||
| 33 | Map<MethodEntry, MethodEntry> accessedToBridge = index.getBridgeMethodIndex().getAccessedToBridge(); | ||
| 34 | for (Map.Entry<MethodEntry, MethodEntry> entry : accessedToBridge.entrySet()) { | ||
| 35 | MethodEntry accessedEntry = entry.getKey(); | ||
| 36 | MethodEntry bridgeEntry = entry.getValue(); | ||
| 37 | |||
| 38 | MethodEntry renamedAccessedEntry = accessedEntry.withName(bridgeEntry.getName()); | ||
| 39 | methods.put(renamedAccessedEntry, methods.remove(accessedEntry)); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | public boolean hasClass(ClassEntry entry) { | 31 | public boolean hasClass(ClassEntry entry) { |
| 44 | return classes.containsKey(entry); | 32 | return classes.containsKey(entry); |
| 45 | } | 33 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java b/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java index ee28b3e..2b63c5d 100644 --- a/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java | |||
| @@ -8,7 +8,6 @@ import cuchaz.enigma.translation.representation.entry.*; | |||
| 8 | 8 | ||
| 9 | import java.util.Collection; | 9 | import java.util.Collection; |
| 10 | import java.util.Map; | 10 | import java.util.Map; |
| 11 | import java.util.Optional; | ||
| 12 | 11 | ||
| 13 | public class ReferenceIndex implements JarIndexer { | 12 | public class ReferenceIndex implements JarIndexer { |
| 14 | private Multimap<MethodEntry, MethodEntry> methodReferences = HashMultimap.create(); | 13 | private Multimap<MethodEntry, MethodEntry> methodReferences = HashMultimap.create(); |
| @@ -58,30 +57,11 @@ public class ReferenceIndex implements JarIndexer { | |||
| 58 | } | 57 | } |
| 59 | 58 | ||
| 60 | private <E extends Entry<?>> E remap(JarIndex index, E entry) { | 59 | private <E extends Entry<?>> E remap(JarIndex index, E entry) { |
| 61 | E resolvedEntry = index.getEntryResolver().resolveFirstEntry(entry, ResolutionStrategy.RESOLVE_CLOSEST); | 60 | return index.getEntryResolver().resolveFirstEntry(entry, ResolutionStrategy.RESOLVE_CLOSEST); |
| 62 | |||
| 63 | Optional<E> remappedBridge = getRemappedBridge(index, resolvedEntry); | ||
| 64 | return remappedBridge.orElse(resolvedEntry); | ||
| 65 | } | 61 | } |
| 66 | 62 | ||
| 67 | private <E extends Entry<?>, C extends Entry<?>> EntryReference<E, C> remap(JarIndex index, EntryReference<E, C> reference) { | 63 | private <E extends Entry<?>, C extends Entry<?>> EntryReference<E, C> remap(JarIndex index, EntryReference<E, C> reference) { |
| 68 | EntryReference<E, C> resolvedReference = index.getEntryResolver().resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST); | 64 | return index.getEntryResolver().resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST); |
| 69 | |||
| 70 | getRemappedBridge(index, resolvedReference.entry).ifPresent(e -> resolvedReference.entry = e); | ||
| 71 | getRemappedBridge(index, resolvedReference.context).ifPresent(e -> resolvedReference.context = e); | ||
| 72 | |||
| 73 | return resolvedReference; | ||
| 74 | } | ||
| 75 | |||
| 76 | @SuppressWarnings("unchecked") | ||
| 77 | private <E extends Entry<?>> Optional<E> getRemappedBridge(JarIndex index, E entry) { | ||
| 78 | if (entry instanceof MethodEntry) { | ||
| 79 | MethodEntry bridgeEntry = index.getBridgeMethodIndex().getBridgeFromAccessed((MethodEntry) entry); | ||
| 80 | if (bridgeEntry != null) { | ||
| 81 | return Optional.of((E) entry.withName(bridgeEntry.getName())); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | return Optional.empty(); | ||
| 85 | } | 65 | } |
| 86 | 66 | ||
| 87 | public Collection<MethodEntry> getMethodsReferencedBy(MethodEntry entry) { | 67 | public Collection<MethodEntry> getMethodsReferencedBy(MethodEntry entry) { |