From 0f47403d0220757fed189b76e2071e25b1025cb8 Mon Sep 17 00:00:00 2001 From: Runemoro Date: Wed, 3 Jun 2020 13:39:42 -0400 Subject: Split GUI code to separate module (#242) * Split into modules * Post merge compile fixes Co-authored-by: modmuss50 --- .../enigma/analysis/index/BridgeMethodIndex.java | 156 ------------------ .../cuchaz/enigma/analysis/index/EntryIndex.java | 102 ------------ .../enigma/analysis/index/IndexClassVisitor.java | 40 ----- .../analysis/index/IndexReferenceVisitor.java | 180 --------------------- .../enigma/analysis/index/InheritanceIndex.java | 127 --------------- .../cuchaz/enigma/analysis/index/JarIndex.java | 171 -------------------- .../cuchaz/enigma/analysis/index/JarIndexer.java | 28 ---- .../analysis/index/PackageVisibilityIndex.java | 147 ----------------- .../enigma/analysis/index/ReferenceIndex.java | 148 ----------------- 9 files changed, 1099 deletions(-) delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/JarIndex.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java (limited to 'src/main/java/cuchaz/enigma/analysis/index') diff --git a/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java b/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java deleted file mode 100644 index a4b1aac..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java +++ /dev/null @@ -1,156 +0,0 @@ -package cuchaz.enigma.analysis.index; - -import com.google.common.collect.Maps; -import cuchaz.enigma.translation.representation.AccessFlags; -import cuchaz.enigma.translation.representation.MethodDescriptor; -import cuchaz.enigma.translation.representation.TypeDescriptor; -import cuchaz.enigma.translation.representation.entry.ClassEntry; -import cuchaz.enigma.translation.representation.entry.MethodDefEntry; -import cuchaz.enigma.translation.representation.entry.MethodEntry; - -import javax.annotation.Nullable; -import java.util.*; - -public class BridgeMethodIndex implements JarIndexer { - private final EntryIndex entryIndex; - private final InheritanceIndex inheritanceIndex; - private final ReferenceIndex referenceIndex; - - private final Map bridgeToSpecialized = Maps.newHashMap(); - private final Map specializedToBridge = Maps.newHashMap(); - - public BridgeMethodIndex(EntryIndex entryIndex, InheritanceIndex inheritanceIndex, ReferenceIndex referenceIndex) { - this.entryIndex = entryIndex; - this.inheritanceIndex = inheritanceIndex; - this.referenceIndex = referenceIndex; - } - - public void findBridgeMethods() { - // look for access and bridged methods - for (MethodEntry methodEntry : entryIndex.getMethods()) { - MethodDefEntry methodDefEntry = (MethodDefEntry) methodEntry; - - AccessFlags access = methodDefEntry.getAccess(); - if (access == null || !access.isSynthetic()) { - continue; - } - - indexSyntheticMethod(methodDefEntry, access); - } - } - - @Override - public void processIndex(JarIndex index) { - Map copiedAccessToBridge = new HashMap<>(specializedToBridge); - - for (Map.Entry entry : copiedAccessToBridge.entrySet()) { - MethodEntry specializedEntry = entry.getKey(); - MethodEntry bridgeEntry = entry.getValue(); - if (bridgeEntry.getName().equals(specializedEntry.getName())) { - continue; - } - - MethodEntry renamedSpecializedEntry = specializedEntry.withName(bridgeEntry.getName()); - specializedToBridge.put(renamedSpecializedEntry, specializedToBridge.get(specializedEntry)); - } - } - - private void indexSyntheticMethod(MethodDefEntry syntheticMethod, AccessFlags access) { - MethodEntry specializedMethod = findSpecializedMethod(syntheticMethod); - if (specializedMethod == null) { - return; - } - - if (access.isBridge() || isPotentialBridge(syntheticMethod, specializedMethod)) { - bridgeToSpecialized.put(syntheticMethod, specializedMethod); - specializedToBridge.put(specializedMethod, syntheticMethod); - } - } - - private MethodEntry findSpecializedMethod(MethodEntry method) { - // we want to find all compiler-added methods that directly call another with no processing - - // get all the methods that we call - final Collection referencedMethods = referenceIndex.getMethodsReferencedBy(method); - - // is there just one? - if (referencedMethods.size() != 1) { - return null; - } - - return referencedMethods.stream().findFirst().orElse(null); - } - - private boolean isPotentialBridge(MethodDefEntry bridgeMethod, MethodEntry specializedMethod) { - // Bridge methods only exist for inheritance purposes, if we're private, final, or static, we cannot be inherited - AccessFlags bridgeAccess = bridgeMethod.getAccess(); - if (bridgeAccess.isPrivate() || bridgeAccess.isFinal() || bridgeAccess.isStatic()) { - return false; - } - - MethodDescriptor bridgeDesc = bridgeMethod.getDesc(); - MethodDescriptor specializedDesc = specializedMethod.getDesc(); - List bridgeArguments = bridgeDesc.getArgumentDescs(); - List specializedArguments = specializedDesc.getArgumentDescs(); - - // A bridge method will always have the same number of arguments - if (bridgeArguments.size() != specializedArguments.size()) { - return false; - } - - // Check that all argument types are bridge-compatible - for (int i = 0; i < bridgeArguments.size(); i++) { - if (!areTypesBridgeCompatible(bridgeArguments.get(i), specializedArguments.get(i))) { - return false; - } - } - - // Check that the return type is bridge-compatible - return areTypesBridgeCompatible(bridgeDesc.getReturnDesc(), specializedDesc.getReturnDesc()); - } - - private boolean areTypesBridgeCompatible(TypeDescriptor bridgeDesc, TypeDescriptor specializedDesc) { - if (bridgeDesc.equals(specializedDesc)) { - return true; - } - - // Either the descs will be equal, or they are both types and different through a generic - if (bridgeDesc.isType() && specializedDesc.isType()) { - ClassEntry bridgeType = bridgeDesc.getTypeEntry(); - ClassEntry accessedType = specializedDesc.getTypeEntry(); - - // If the given types are completely unrelated to each other, this can't be bridge compatible - InheritanceIndex.Relation relation = inheritanceIndex.computeClassRelation(accessedType, bridgeType); - return relation != InheritanceIndex.Relation.UNRELATED; - } - - return false; - } - - public boolean isBridgeMethod(MethodEntry entry) { - return bridgeToSpecialized.containsKey(entry); - } - - public boolean isSpecializedMethod(MethodEntry entry) { - return specializedToBridge.containsKey(entry); - } - - @Nullable - public MethodEntry getBridgeFromSpecialized(MethodEntry specialized) { - return specializedToBridge.get(specialized); - } - - public MethodEntry getSpecializedFromBridge(MethodEntry bridge) { - return bridgeToSpecialized.get(bridge); - } - - /** Includes "renamed specialized -> bridge" entries. */ - public Map getSpecializedToBridge() { - return Collections.unmodifiableMap(specializedToBridge); - } - - /** Only "bridge -> original name" entries. **/ - public Map getBridgeToSpecialized() { - return Collections.unmodifiableMap(bridgeToSpecialized); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java b/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java deleted file mode 100644 index 9a2726e..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java +++ /dev/null @@ -1,102 +0,0 @@ -package cuchaz.enigma.analysis.index; - -import cuchaz.enigma.translation.representation.AccessFlags; -import cuchaz.enigma.translation.representation.entry.*; - -import javax.annotation.Nullable; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -public class EntryIndex implements JarIndexer { - private Map classes = new HashMap<>(); - private Map fields = new HashMap<>(); - private Map methods = new HashMap<>(); - private Map definitions = new HashMap<>(); - - @Override - public void indexClass(ClassDefEntry classEntry) { - definitions.put(classEntry, classEntry); - classes.put(classEntry, classEntry.getAccess()); - } - - @Override - public void indexMethod(MethodDefEntry methodEntry) { - methods.put(methodEntry, methodEntry.getAccess()); - } - - @Override - public void indexField(FieldDefEntry fieldEntry) { - fields.put(fieldEntry, fieldEntry.getAccess()); - } - - public boolean hasClass(ClassEntry entry) { - return classes.containsKey(entry); - } - - public boolean hasMethod(MethodEntry entry) { - return methods.containsKey(entry); - } - - public boolean hasField(FieldEntry entry) { - return fields.containsKey(entry); - } - - public boolean hasEntry(Entry entry) { - if (entry instanceof ClassEntry) { - return hasClass((ClassEntry) entry); - } else if (entry instanceof MethodEntry) { - return hasMethod((MethodEntry) entry); - } else if (entry instanceof FieldEntry) { - return hasField((FieldEntry) entry); - } else if (entry instanceof LocalVariableEntry) { - return hasMethod(((LocalVariableEntry) entry).getParent()); - } - - return false; - } - - @Nullable - public AccessFlags getMethodAccess(MethodEntry entry) { - return methods.get(entry); - } - - @Nullable - public AccessFlags getFieldAccess(FieldEntry entry) { - return fields.get(entry); - } - - @Nullable - public AccessFlags getClassAccess(ClassEntry entry) { - return classes.get(entry); - } - - @Nullable - public AccessFlags getEntryAccess(Entry entry) { - if (entry instanceof MethodEntry) { - return getMethodAccess((MethodEntry) entry); - } else if (entry instanceof FieldEntry) { - return getFieldAccess((FieldEntry) entry); - } else if (entry instanceof LocalVariableEntry) { - return getMethodAccess(((LocalVariableEntry) entry).getParent()); - } - - return null; - } - - public ClassDefEntry getDefinition(ClassEntry entry) { - return definitions.get(entry); - } - - public Collection getClasses() { - return classes.keySet(); - } - - public Collection getMethods() { - return methods.keySet(); - } - - public Collection getFields() { - return fields.keySet(); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java b/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java deleted file mode 100644 index f9cb23c..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java +++ /dev/null @@ -1,40 +0,0 @@ -package cuchaz.enigma.analysis.index; - -import cuchaz.enigma.translation.representation.entry.ClassDefEntry; -import cuchaz.enigma.translation.representation.entry.FieldDefEntry; -import cuchaz.enigma.translation.representation.entry.MethodDefEntry; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.MethodVisitor; - -public class IndexClassVisitor extends ClassVisitor { - private final JarIndexer indexer; - private ClassDefEntry classEntry; - - public IndexClassVisitor(JarIndex indexer, int api) { - super(api); - this.indexer = indexer; - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - classEntry = ClassDefEntry.parse(access, name, signature, superName, interfaces); - indexer.indexClass(classEntry); - - super.visit(version, access, name, signature, superName, interfaces); - } - - @Override - public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { - indexer.indexField(FieldDefEntry.parse(classEntry, access, name, desc, signature)); - - return super.visitField(access, name, desc, signature, value); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - indexer.indexMethod(MethodDefEntry.parse(classEntry, access, name, desc, signature)); - - return super.visitMethod(access, name, desc, signature, exceptions); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java b/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java deleted file mode 100644 index f3d419e..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java +++ /dev/null @@ -1,180 +0,0 @@ -package cuchaz.enigma.analysis.index; - -import cuchaz.enigma.analysis.IndexSimpleVerifier; -import cuchaz.enigma.analysis.InterpreterPair; -import cuchaz.enigma.analysis.MethodNodeWithAction; -import cuchaz.enigma.analysis.ReferenceTargetType; -import cuchaz.enigma.translation.representation.AccessFlags; -import cuchaz.enigma.translation.representation.Lambda; -import cuchaz.enigma.translation.representation.MethodDescriptor; -import cuchaz.enigma.translation.representation.Signature; -import cuchaz.enigma.translation.representation.entry.*; -import org.objectweb.asm.*; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.InvokeDynamicInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.analysis.*; - -import java.util.List; -import java.util.stream.Collectors; - -public class IndexReferenceVisitor extends ClassVisitor { - private final JarIndexer indexer; - private final EntryIndex entryIndex; - private final InheritanceIndex inheritanceIndex; - private ClassEntry classEntry; - private String className; - - public IndexReferenceVisitor(JarIndexer indexer, EntryIndex entryIndex, InheritanceIndex inheritanceIndex, int api) { - super(api); - this.indexer = indexer; - this.entryIndex = entryIndex; - this.inheritanceIndex = inheritanceIndex; - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - classEntry = new ClassEntry(name); - className = name; - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - MethodDefEntry entry = new MethodDefEntry(classEntry, name, new MethodDescriptor(desc), Signature.createSignature(signature), new AccessFlags(access)); - return new MethodNodeWithAction(api, access, name, desc, signature, exceptions, methodNode -> { - try { - new Analyzer<>(new MethodInterpreter(entry, indexer, entryIndex, inheritanceIndex)).analyze(className, methodNode); - } catch (AnalyzerException e) { - throw new RuntimeException(e); - } - }); - } - - private static class MethodInterpreter extends InterpreterPair { - private final MethodDefEntry callerEntry; - private JarIndexer indexer; - - public MethodInterpreter(MethodDefEntry callerEntry, JarIndexer indexer, EntryIndex entryIndex, InheritanceIndex inheritanceIndex) { - super(new IndexSimpleVerifier(entryIndex, inheritanceIndex), new SourceInterpreter()); - this.callerEntry = callerEntry; - this.indexer = indexer; - } - - @Override - public PairValue newOperation(AbstractInsnNode insn) throws AnalyzerException { - if (insn.getOpcode() == Opcodes.GETSTATIC) { - FieldInsnNode field = (FieldInsnNode) insn; - indexer.indexFieldReference(callerEntry, FieldEntry.parse(field.owner, field.name, field.desc), ReferenceTargetType.none()); - } - - return super.newOperation(insn); - } - - @Override - public PairValue unaryOperation(AbstractInsnNode insn, PairValue value) throws AnalyzerException { - if (insn.getOpcode() == Opcodes.PUTSTATIC) { - FieldInsnNode field = (FieldInsnNode) insn; - indexer.indexFieldReference(callerEntry, FieldEntry.parse(field.owner, field.name, field.desc), ReferenceTargetType.none()); - } - - if (insn.getOpcode() == Opcodes.GETFIELD) { - FieldInsnNode field = (FieldInsnNode) insn; - indexer.indexFieldReference(callerEntry, FieldEntry.parse(field.owner, field.name, field.desc), getReferenceTargetType(value, insn)); - } - - return super.unaryOperation(insn, value); - } - - - @Override - public PairValue binaryOperation(AbstractInsnNode insn, PairValue value1, PairValue value2) throws AnalyzerException { - if (insn.getOpcode() == Opcodes.PUTFIELD) { - FieldInsnNode field = (FieldInsnNode) insn; - FieldEntry fieldEntry = FieldEntry.parse(field.owner, field.name, field.desc); - indexer.indexFieldReference(callerEntry, fieldEntry, ReferenceTargetType.none()); - } - - return super.binaryOperation(insn, value1, value2); - } - - @Override - public PairValue naryOperation(AbstractInsnNode insn, List> values) throws AnalyzerException { - if (insn.getOpcode() == Opcodes.INVOKEINTERFACE || insn.getOpcode() == Opcodes.INVOKESPECIAL || insn.getOpcode() == Opcodes.INVOKEVIRTUAL) { - MethodInsnNode methodInsn = (MethodInsnNode) insn; - indexer.indexMethodReference(callerEntry, MethodEntry.parse(methodInsn.owner, methodInsn.name, methodInsn.desc), getReferenceTargetType(values.get(0), insn)); - } - - if (insn.getOpcode() == Opcodes.INVOKESTATIC) { - MethodInsnNode methodInsn = (MethodInsnNode) insn; - indexer.indexMethodReference(callerEntry, MethodEntry.parse(methodInsn.owner, methodInsn.name, methodInsn.desc), ReferenceTargetType.none()); - } - - if (insn.getOpcode() == Opcodes.INVOKEDYNAMIC) { - InvokeDynamicInsnNode invokeDynamicInsn = (InvokeDynamicInsnNode) insn; - List args = values.stream().map(v -> v.right.insns.stream().findFirst().orElseThrow(AssertionError::new)).collect(Collectors.toList()); - - if ("java/lang/invoke/LambdaMetafactory".equals(invokeDynamicInsn.bsm.getOwner()) && "metafactory".equals(invokeDynamicInsn.bsm.getName())) { - Type samMethodType = (Type) invokeDynamicInsn.bsmArgs[0]; - Handle implMethod = (Handle) invokeDynamicInsn.bsmArgs[1]; - Type instantiatedMethodType = (Type) invokeDynamicInsn.bsmArgs[2]; - - ReferenceTargetType targetType; - if (implMethod.getTag() != Opcodes.H_GETSTATIC && implMethod.getTag() != Opcodes.H_PUTFIELD && implMethod.getTag() != Opcodes.H_INVOKESTATIC) { - if (instantiatedMethodType.getArgumentTypes().length < Type.getArgumentTypes(implMethod.getDesc()).length) { - targetType = getReferenceTargetType(values.get(0), insn); - } else { - targetType = ReferenceTargetType.none(); // no "this" argument - } - } else { - targetType = ReferenceTargetType.none(); - } - - indexer.indexLambda(callerEntry, new Lambda( - invokeDynamicInsn.name, - new MethodDescriptor(invokeDynamicInsn.desc), - new MethodDescriptor(samMethodType.getDescriptor()), - getHandleEntry(implMethod), - new MethodDescriptor(instantiatedMethodType.getDescriptor()) - ), targetType); - } - } - - return super.naryOperation(insn, values); - } - - private ReferenceTargetType getReferenceTargetType(PairValue target, AbstractInsnNode insn) throws AnalyzerException { - if (target.left == BasicValue.UNINITIALIZED_VALUE) { - return ReferenceTargetType.uninitialized(); - } - - if (target.left.getType().getSort() == Type.OBJECT) { - return ReferenceTargetType.classType(new ClassEntry(target.left.getType().getInternalName())); - } - - if (target.left.getType().getSort() == Type.ARRAY) { - return ReferenceTargetType.classType(new ClassEntry("java/lang/Object")); - } - - throw new AnalyzerException(insn, "called method on or accessed field of non-object type"); - } - - private static ParentedEntry getHandleEntry(Handle handle) { - switch (handle.getTag()) { - case Opcodes.H_GETFIELD: - case Opcodes.H_GETSTATIC: - case Opcodes.H_PUTFIELD: - case Opcodes.H_PUTSTATIC: - return FieldEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc()); - case Opcodes.H_INVOKEINTERFACE: - case Opcodes.H_INVOKESPECIAL: - case Opcodes.H_INVOKESTATIC: - case Opcodes.H_INVOKEVIRTUAL: - case Opcodes.H_NEWINVOKESPECIAL: - return MethodEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc()); - } - - throw new RuntimeException("Invalid handle tag " + handle.getTag()); - } - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java b/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java deleted file mode 100644 index 1ab2abd..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java +++ /dev/null @@ -1,127 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - *

- * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ - -package cuchaz.enigma.analysis.index; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; -import cuchaz.enigma.translation.representation.entry.ClassDefEntry; -import cuchaz.enigma.translation.representation.entry.ClassEntry; - -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Set; - -public class InheritanceIndex implements JarIndexer { - private final EntryIndex entryIndex; - - private Multimap classParents = HashMultimap.create(); - private Multimap classChildren = HashMultimap.create(); - - public InheritanceIndex(EntryIndex entryIndex) { - this.entryIndex = entryIndex; - } - - @Override - public void indexClass(ClassDefEntry classEntry) { - if (classEntry.isJre()) { - return; - } - - ClassEntry superClass = classEntry.getSuperClass(); - if (superClass != null && !superClass.getName().equals("java/lang/Object")) { - indexParent(classEntry, superClass); - } - - for (ClassEntry interfaceEntry : classEntry.getInterfaces()) { - indexParent(classEntry, interfaceEntry); - } - } - - private void indexParent(ClassEntry childEntry, ClassEntry parentEntry) { - classParents.put(childEntry, parentEntry); - classChildren.put(parentEntry, childEntry); - } - - public Collection getParents(ClassEntry classEntry) { - return classParents.get(classEntry); - } - - public Collection getChildren(ClassEntry classEntry) { - return classChildren.get(classEntry); - } - - public Collection getDescendants(ClassEntry classEntry) { - Collection descendants = new HashSet<>(); - - LinkedList descendantQueue = new LinkedList<>(); - descendantQueue.push(classEntry); - - while (!descendantQueue.isEmpty()) { - ClassEntry descendant = descendantQueue.pop(); - Collection children = getChildren(descendant); - - children.forEach(descendantQueue::push); - descendants.addAll(children); - } - - return descendants; - } - - public Set getAncestors(ClassEntry classEntry) { - Set ancestors = Sets.newHashSet(); - - LinkedList ancestorQueue = new LinkedList<>(); - ancestorQueue.push(classEntry); - - while (!ancestorQueue.isEmpty()) { - ClassEntry ancestor = ancestorQueue.pop(); - Collection parents = getParents(ancestor); - - parents.forEach(ancestorQueue::push); - ancestors.addAll(parents); - } - - return ancestors; - } - - public Relation computeClassRelation(ClassEntry classEntry, ClassEntry potentialAncestor) { - if (potentialAncestor.getName().equals("java/lang/Object")) return Relation.RELATED; - if (!entryIndex.hasClass(classEntry)) return Relation.UNKNOWN; - - for (ClassEntry ancestor : getAncestors(classEntry)) { - if (potentialAncestor.equals(ancestor)) { - return Relation.RELATED; - } else if (!entryIndex.hasClass(ancestor)) { - return Relation.UNKNOWN; - } - } - - return Relation.UNRELATED; - } - - public boolean isParent(ClassEntry classEntry) { - return classChildren.containsKey(classEntry); - } - - public boolean hasParents(ClassEntry classEntry) { - Collection parents = classParents.get(classEntry); - return parents != null && !parents.isEmpty(); - } - - public enum Relation { - RELATED, - UNRELATED, - UNKNOWN - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java deleted file mode 100644 index e401c2f..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java +++ /dev/null @@ -1,171 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - *

- * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ - -package cuchaz.enigma.analysis.index; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import cuchaz.enigma.ProgressListener; -import cuchaz.enigma.analysis.ClassCache; -import cuchaz.enigma.analysis.ReferenceTargetType; -import cuchaz.enigma.translation.mapping.EntryResolver; -import cuchaz.enigma.translation.mapping.IndexEntryResolver; -import cuchaz.enigma.translation.representation.Lambda; -import cuchaz.enigma.translation.representation.entry.*; -import cuchaz.enigma.utils.I18n; - -import cuchaz.enigma.utils.Utils; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.Opcodes; - -import java.util.Arrays; -import java.util.Collection; - -public class JarIndex implements JarIndexer { - private final EntryIndex entryIndex; - private final InheritanceIndex inheritanceIndex; - private final ReferenceIndex referenceIndex; - private final BridgeMethodIndex bridgeMethodIndex; - private final PackageVisibilityIndex packageVisibilityIndex; - private final EntryResolver entryResolver; - - private final Collection indexers; - - private final Multimap methodImplementations = HashMultimap.create(); - - public JarIndex(EntryIndex entryIndex, InheritanceIndex inheritanceIndex, ReferenceIndex referenceIndex, BridgeMethodIndex bridgeMethodIndex, PackageVisibilityIndex packageVisibilityIndex) { - this.entryIndex = entryIndex; - this.inheritanceIndex = inheritanceIndex; - this.referenceIndex = referenceIndex; - this.bridgeMethodIndex = bridgeMethodIndex; - this.packageVisibilityIndex = packageVisibilityIndex; - this.indexers = Arrays.asList(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex, packageVisibilityIndex); - this.entryResolver = new IndexEntryResolver(this); - } - - public static JarIndex empty() { - EntryIndex entryIndex = new EntryIndex(); - InheritanceIndex inheritanceIndex = new InheritanceIndex(entryIndex); - ReferenceIndex referenceIndex = new ReferenceIndex(); - BridgeMethodIndex bridgeMethodIndex = new BridgeMethodIndex(entryIndex, inheritanceIndex, referenceIndex); - PackageVisibilityIndex packageVisibilityIndex = new PackageVisibilityIndex(); - return new JarIndex(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex, packageVisibilityIndex); - } - - public void indexJar(ClassCache classCache, ProgressListener progress) { - progress.init(4, I18n.translate("progress.jar.indexing")); - - progress.step(1, I18n.translate("progress.jar.indexing.entries")); - classCache.visit(() -> new IndexClassVisitor(this, Utils.ASM_VERSION), ClassReader.SKIP_CODE); - - progress.step(2, I18n.translate("progress.jar.indexing.references")); - classCache.visit(() -> new IndexReferenceVisitor(this, entryIndex, inheritanceIndex, Utils.ASM_VERSION), 0); - - progress.step(3, I18n.translate("progress.jar.indexing.methods")); - bridgeMethodIndex.findBridgeMethods(); - - progress.step(4, I18n.translate("progress.jar.indexing.process")); - processIndex(this); - } - - @Override - public void processIndex(JarIndex index) { - indexers.forEach(indexer -> indexer.processIndex(index)); - } - - @Override - public void indexClass(ClassDefEntry classEntry) { - if (classEntry.isJre()) { - return; - } - - for (ClassEntry interfaceEntry : classEntry.getInterfaces()) { - if (classEntry.equals(interfaceEntry)) { - throw new IllegalArgumentException("Class cannot be its own interface! " + classEntry); - } - } - - indexers.forEach(indexer -> indexer.indexClass(classEntry)); - } - - @Override - public void indexField(FieldDefEntry fieldEntry) { - if (fieldEntry.getParent().isJre()) { - return; - } - - indexers.forEach(indexer -> indexer.indexField(fieldEntry)); - } - - @Override - public void indexMethod(MethodDefEntry methodEntry) { - if (methodEntry.getParent().isJre()) { - return; - } - - indexers.forEach(indexer -> indexer.indexMethod(methodEntry)); - - if (!methodEntry.isConstructor()) { - methodImplementations.put(methodEntry.getParent().getFullName(), methodEntry); - } - } - - @Override - public void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry, ReferenceTargetType targetType) { - if (callerEntry.getParent().isJre()) { - return; - } - - indexers.forEach(indexer -> indexer.indexMethodReference(callerEntry, referencedEntry, targetType)); - } - - @Override - public void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry, ReferenceTargetType targetType) { - if (callerEntry.getParent().isJre()) { - return; - } - - indexers.forEach(indexer -> indexer.indexFieldReference(callerEntry, referencedEntry, targetType)); - } - - @Override - public void indexLambda(MethodDefEntry callerEntry, Lambda lambda, ReferenceTargetType targetType) { - if (callerEntry.getParent().isJre()) { - return; - } - - indexers.forEach(indexer -> indexer.indexLambda(callerEntry, lambda, targetType)); - } - - public EntryIndex getEntryIndex() { - return entryIndex; - } - - public InheritanceIndex getInheritanceIndex() { - return this.inheritanceIndex; - } - - public ReferenceIndex getReferenceIndex() { - return referenceIndex; - } - - public BridgeMethodIndex getBridgeMethodIndex() { - return bridgeMethodIndex; - } - - public PackageVisibilityIndex getPackageVisibilityIndex() { - return packageVisibilityIndex; - } - - public EntryResolver getEntryResolver() { - return entryResolver; - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java b/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java deleted file mode 100644 index f17e7c9..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java +++ /dev/null @@ -1,28 +0,0 @@ -package cuchaz.enigma.analysis.index; - -import cuchaz.enigma.analysis.ReferenceTargetType; -import cuchaz.enigma.translation.representation.Lambda; -import cuchaz.enigma.translation.representation.entry.*; - -public interface JarIndexer { - default void indexClass(ClassDefEntry classEntry) { - } - - default void indexField(FieldDefEntry fieldEntry) { - } - - default void indexMethod(MethodDefEntry methodEntry) { - } - - default void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry, ReferenceTargetType targetType) { - } - - default void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry, ReferenceTargetType targetType) { - } - - default void indexLambda(MethodDefEntry callerEntry, Lambda lambda, ReferenceTargetType targetType) { - } - - default void processIndex(JarIndex index) { - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java b/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java deleted file mode 100644 index 63eb730..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java +++ /dev/null @@ -1,147 +0,0 @@ -package cuchaz.enigma.analysis.index; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.analysis.ReferenceTargetType; -import cuchaz.enigma.translation.representation.AccessFlags; -import cuchaz.enigma.translation.representation.entry.*; - -import java.util.*; - -public class PackageVisibilityIndex implements JarIndexer { - private static boolean requiresSamePackage(AccessFlags entryAcc, EntryReference ref, InheritanceIndex inheritanceIndex) { - if (entryAcc.isPublic()) { - return false; - } - - if (entryAcc.isProtected()) { - ClassEntry contextClass = ref.context.getContainingClass(); - ClassEntry referencedClass = ref.entry.getContainingClass(); - - if (!inheritanceIndex.getAncestors(contextClass).contains(referencedClass)) { - return true; // access to protected member not in superclass - } - - if (ref.targetType.getKind() == ReferenceTargetType.Kind.NONE) { - return false; // access to superclass or static superclass member - } - - // access to instance member only valid if target's class assignable to context class - return !(ref.targetType.getKind() == ReferenceTargetType.Kind.UNINITIALIZED || - ((ReferenceTargetType.ClassType) ref.targetType).getEntry().equals(contextClass) || - inheritanceIndex.getAncestors(((ReferenceTargetType.ClassType) ref.targetType).getEntry()).contains(contextClass)); - } - - return true; - } - - private final HashMultimap connections = HashMultimap.create(); - private final List> partitions = Lists.newArrayList(); - private final Map> classPartitions = Maps.newHashMap(); - - private void addConnection(ClassEntry classA, ClassEntry classB) { - if (classA != classB) { - connections.put(classA, classB); - connections.put(classB, classA); - } - } - - private void buildPartition(Set unassignedClasses, Set partition, ClassEntry member) { - for (ClassEntry connected : connections.get(member)) { - if (unassignedClasses.remove(connected)) { - partition.add(connected); - buildPartition(unassignedClasses, partition, connected); - } - } - } - - private void addConnections(EntryIndex entryIndex, ReferenceIndex referenceIndex, InheritanceIndex inheritanceIndex) { - for (FieldEntry entry : entryIndex.getFields()) { - AccessFlags entryAcc = entryIndex.getFieldAccess(entry); - if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { - for (EntryReference ref : referenceIndex.getReferencesToField(entry)) { - if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { - addConnection(ref.entry.getContainingClass(), ref.context.getContainingClass()); - } - } - } - } - - for (MethodEntry entry : entryIndex.getMethods()) { - AccessFlags entryAcc = entryIndex.getMethodAccess(entry); - if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { - for (EntryReference ref : referenceIndex.getReferencesToMethod(entry)) { - if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { - addConnection(ref.entry.getContainingClass(), ref.context.getContainingClass()); - } - } - } - } - - for (ClassEntry entry : entryIndex.getClasses()) { - AccessFlags entryAcc = entryIndex.getClassAccess(entry); - if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { - for (EntryReference ref : referenceIndex.getFieldTypeReferencesToClass(entry)) { - if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { - addConnection(ref.entry.getContainingClass(), ref.context.getContainingClass()); - } - } - - for (EntryReference ref : referenceIndex.getMethodTypeReferencesToClass(entry)) { - if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { - addConnection(ref.entry.getContainingClass(), ref.context.getContainingClass()); - } - } - } - - for (ClassEntry parent : inheritanceIndex.getParents(entry)) { - AccessFlags parentAcc = entryIndex.getClassAccess(parent); - if (parentAcc != null && !parentAcc.isPublic() && !parentAcc.isPrivate()) { - addConnection(entry, parent); - } - } - - ClassEntry outerClass = entry.getOuterClass(); - if (outerClass != null) { - addConnection(entry, outerClass); - } - } - } - - private void addPartitions(EntryIndex entryIndex) { - Set unassignedClasses = Sets.newHashSet(entryIndex.getClasses()); - while (!unassignedClasses.isEmpty()) { - Iterator iterator = unassignedClasses.iterator(); - ClassEntry initialEntry = iterator.next(); - iterator.remove(); - - HashSet partition = Sets.newHashSet(); - partition.add(initialEntry); - buildPartition(unassignedClasses, partition, initialEntry); - partitions.add(partition); - for (ClassEntry entry : partition) { - classPartitions.put(entry, partition); - } - } - } - - public Collection> getPartitions() { - return partitions; - } - - public Set getPartition(ClassEntry classEntry) { - return classPartitions.get(classEntry); - } - - @Override - public void processIndex(JarIndex index) { - EntryIndex entryIndex = index.getEntryIndex(); - ReferenceIndex referenceIndex = index.getReferenceIndex(); - InheritanceIndex inheritanceIndex = index.getInheritanceIndex(); - addConnections(entryIndex, referenceIndex, inheritanceIndex); - addPartitions(entryIndex); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java b/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java deleted file mode 100644 index b6797c2..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java +++ /dev/null @@ -1,148 +0,0 @@ -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 methodReferences = HashMultimap.create(); - - private Multimap> referencesToMethods = HashMultimap.create(); - private Multimap> referencesToClasses = HashMultimap.create(); - private Multimap> referencesToFields = HashMultimap.create(); - private Multimap> fieldTypeReferences = HashMultimap.create(); - private Multimap> 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 , V extends Entry> Multimap remapReferences(JarIndex index, Multimap multimap) { - final int keySetSize = multimap.keySet().size(); - Multimap resolved = HashMultimap.create(multimap.keySet().size(), keySetSize == 0 ? 0 : multimap.size() / keySetSize); - for (Map.Entry entry : multimap.entries()) { - resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue())); - } - return resolved; - } - - private , C extends Entry> Multimap> remapReferencesTo(JarIndex index, Multimap> multimap) { - final int keySetSize = multimap.keySet().size(); - Multimap> resolved = HashMultimap.create(keySetSize, keySetSize == 0 ? 0 : multimap.size() / keySetSize); - for (Map.Entry> entry : multimap.entries()) { - resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue())); - } - return resolved; - } - - private > E remap(JarIndex index, E entry) { - return index.getEntryResolver().resolveFirstEntry(entry, ResolutionStrategy.RESOLVE_CLOSEST); - } - - private , C extends Entry> EntryReference remap(JarIndex index, EntryReference reference) { - return index.getEntryResolver().resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST); - } - - public Collection getMethodsReferencedBy(MethodEntry entry) { - return methodReferences.get(entry); - } - - public Collection> getReferencesToField(FieldEntry entry) { - return referencesToFields.get(entry); - } - - public Collection> getReferencesToClass(ClassEntry entry) { - return referencesToClasses.get(entry); - } - - public Collection> getReferencesToMethod(MethodEntry entry) { - return referencesToMethods.get(entry); - } - - public Collection> getFieldTypeReferencesToClass(ClassEntry entry) { - return fieldTypeReferences.get(entry); - } - - public Collection> getMethodTypeReferencesToClass(ClassEntry entry) { - return methodTypeReferences.get(entry); - } -} -- cgit v1.2.3