summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/analysis
diff options
context:
space:
mode:
authorGravatar gegy10002019-06-16 23:49:25 +0200
committerGravatar gegy10002019-06-16 23:49:25 +0200
commite27d5967029f4f3da8889dd673ba516dcd9f3ac8 (patch)
tree71c98afad01cafdb2884da288e494e8761c2a8ff /src/main/java/cuchaz/enigma/analysis
parentMerge remote-tracking branch 'origin/master' into proposal-tweak (diff)
downloadenigma-fork-e27d5967029f4f3da8889dd673ba516dcd9f3ac8.tar.gz
enigma-fork-e27d5967029f4f3da8889dd673ba516dcd9f3ac8.tar.xz
enigma-fork-e27d5967029f4f3da8889dd673ba516dcd9f3ac8.zip
Plugin rework along with API rework: Enigma split from EnigmaProject; plugins now provide services configurable via a profile
Diffstat (limited to 'src/main/java/cuchaz/enigma/analysis')
-rw-r--r--src/main/java/cuchaz/enigma/analysis/ClassCache.java127
-rw-r--r--src/main/java/cuchaz/enigma/analysis/ParsedJar.java129
-rw-r--r--src/main/java/cuchaz/enigma/analysis/index/JarIndex.java22
3 files changed, 139 insertions, 139 deletions
diff --git a/src/main/java/cuchaz/enigma/analysis/ClassCache.java b/src/main/java/cuchaz/enigma/analysis/ClassCache.java
new file mode 100644
index 0000000..0bd78b3
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/analysis/ClassCache.java
@@ -0,0 +1,127 @@
1package cuchaz.enigma.analysis;
2
3import com.google.common.cache.Cache;
4import com.google.common.cache.CacheBuilder;
5import com.google.common.collect.ImmutableSet;
6import cuchaz.enigma.CompiledSource;
7import cuchaz.enigma.ProgressListener;
8import cuchaz.enigma.analysis.index.JarIndex;
9import cuchaz.enigma.bytecode.translators.LocalVariableFixVisitor;
10import org.objectweb.asm.ClassReader;
11import org.objectweb.asm.ClassVisitor;
12import org.objectweb.asm.Opcodes;
13import org.objectweb.asm.tree.ClassNode;
14
15import javax.annotation.Nullable;
16import java.io.IOException;
17import java.nio.file.FileSystem;
18import java.nio.file.FileSystems;
19import java.nio.file.Files;
20import java.nio.file.Path;
21import java.util.concurrent.ExecutionException;
22import java.util.concurrent.TimeUnit;
23import java.util.function.Supplier;
24
25public final class ClassCache implements AutoCloseable, CompiledSource {
26 private final FileSystem fileSystem;
27 private final ImmutableSet<String> classNames;
28
29 private final Cache<String, ClassNode> nodeCache = CacheBuilder.newBuilder()
30 .maximumSize(128)
31 .expireAfterAccess(1, TimeUnit.MINUTES)
32 .build();
33
34 private ClassCache(FileSystem fileSystem, ImmutableSet<String> classNames) {
35 this.fileSystem = fileSystem;
36 this.classNames = classNames;
37 }
38
39 public static ClassCache of(Path jarPath) throws IOException {
40 FileSystem fileSystem = FileSystems.newFileSystem(jarPath, null);
41 ImmutableSet<String> classNames = collectClassNames(fileSystem);
42
43 return new ClassCache(fileSystem, classNames);
44 }
45
46 private static ImmutableSet<String> collectClassNames(FileSystem fileSystem) throws IOException {
47 ImmutableSet.Builder<String> classNames = ImmutableSet.builder();
48 for (Path root : fileSystem.getRootDirectories()) {
49 Files.walk(root).map(Path::toString)
50 .forEach(path -> {
51 if (path.endsWith(".class")) {
52 String name = path.substring(1, path.length() - ".class".length());
53 classNames.add(name);
54 }
55 });
56 }
57
58 return classNames.build();
59 }
60
61 @Nullable
62 @Override
63 public ClassNode getClassNode(String name) {
64 if (!classNames.contains(name)) {
65 return null;
66 }
67
68 try {
69 return nodeCache.get(name, () -> parseNode(name));
70 } catch (ExecutionException e) {
71 throw new RuntimeException(e);
72 }
73 }
74
75 private ClassNode parseNode(String name) throws IOException {
76 ClassReader reader = getReader(name);
77
78 ClassNode node = new ClassNode();
79
80 LocalVariableFixVisitor visitor = new LocalVariableFixVisitor(Opcodes.ASM5, node);
81 reader.accept(visitor, 0);
82
83 return node;
84 }
85
86 private ClassReader getReader(String name) throws IOException {
87 Path path = fileSystem.getPath(name + ".class");
88
89 byte[] bytes = Files.readAllBytes(path);
90 return new ClassReader(bytes);
91 }
92
93 public int getClassCount() {
94 return classNames.size();
95 }
96
97 public void visit(Supplier<ClassVisitor> visitorSupplier, int readFlags) {
98 for (String className : classNames) {
99 ClassVisitor visitor = visitorSupplier.get();
100
101 ClassNode cached = nodeCache.getIfPresent(className);
102 if (cached != null) {
103 cached.accept(visitor);
104 continue;
105 }
106
107 try {
108 ClassReader reader = getReader(className);
109 reader.accept(visitor, readFlags);
110 } catch (IOException e) {
111 System.out.println("Failed to visit class " + className);
112 e.printStackTrace();
113 }
114 }
115 }
116
117 @Override
118 public void close() throws IOException {
119 this.fileSystem.close();
120 }
121
122 public JarIndex index(ProgressListener progress) {
123 JarIndex index = JarIndex.empty();
124 index.indexJar(this, progress);
125 return index;
126 }
127}
diff --git a/src/main/java/cuchaz/enigma/analysis/ParsedJar.java b/src/main/java/cuchaz/enigma/analysis/ParsedJar.java
deleted file mode 100644
index ddcda3e..0000000
--- a/src/main/java/cuchaz/enigma/analysis/ParsedJar.java
+++ /dev/null
@@ -1,129 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html
7 * <p>
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11
12package cuchaz.enigma.analysis;
13
14import com.google.common.io.ByteStreams;
15import cuchaz.enigma.CompiledSource;
16import cuchaz.enigma.bytecode.translators.LocalVariableFixVisitor;
17import cuchaz.enigma.translation.representation.entry.ClassEntry;
18import org.objectweb.asm.ClassReader;
19import org.objectweb.asm.ClassVisitor;
20import org.objectweb.asm.Opcodes;
21import org.objectweb.asm.tree.ClassNode;
22
23import javax.annotation.Nullable;
24import java.io.BufferedInputStream;
25import java.io.IOException;
26import java.io.InputStream;
27import java.util.*;
28import java.util.function.Consumer;
29import java.util.function.Function;
30import java.util.jar.JarEntry;
31import java.util.jar.JarFile;
32import java.util.jar.JarInputStream;
33
34public class ParsedJar implements CompiledSource {
35 private final Map<String, byte[]> classBytes;
36 private final Map<String, ClassNode> nodeCache = new HashMap<>();
37
38 public ParsedJar(JarFile jar) throws IOException {
39 Map<String, byte[]> uClassBytes = new LinkedHashMap<>();
40 try {
41 // get the jar entries that correspond to classes
42 Enumeration<JarEntry> entries = jar.entries();
43 while (entries.hasMoreElements()) {
44 JarEntry entry = entries.nextElement();
45 // is this a class file?
46 if (entry.getName().endsWith(".class")) {
47 try (InputStream input = new BufferedInputStream(jar.getInputStream(entry))) {
48 String path = entry.getName().substring(0, entry.getName().length() - ".class".length());
49 uClassBytes.put(path, ByteStreams.toByteArray(input));
50 }
51 }
52 }
53 } finally {
54 jar.close();
55 classBytes = Collections.unmodifiableMap(uClassBytes);
56 }
57 }
58
59 public ParsedJar(JarInputStream jar) throws IOException {
60 Map<String, byte[]> uClassBytes = new LinkedHashMap<>();
61 try {
62 // get the jar entries that correspond to classes
63 JarEntry entry;
64 while ((entry = jar.getNextJarEntry()) != null) {
65 // is this a class file?
66 if (entry.getName().endsWith(".class")) {
67 String path = entry.getName().substring(0, entry.getName().length() - ".class".length());
68 uClassBytes.put(path, ByteStreams.toByteArray(jar));
69 jar.closeEntry();
70 }
71 }
72 } finally {
73 jar.close();
74 classBytes = Collections.unmodifiableMap(uClassBytes);
75 }
76 }
77
78 public void visitReader(Function<String, ClassVisitor> visitorFunction, int options) {
79 for (String s : classBytes.keySet()) {
80 ClassNode nodeCached = nodeCache.get(s);
81 if (nodeCached != null) {
82 nodeCached.accept(visitorFunction.apply(s));
83 } else {
84 new ClassReader(classBytes.get(s)).accept(visitorFunction.apply(s), options);
85 }
86 }
87 }
88
89 public void visitNode(Consumer<ClassNode> consumer) {
90 for (String s : classBytes.keySet()) {
91 consumer.accept(getClassNode(s));
92 }
93 }
94
95 public int getClassCount() {
96 return classBytes.size();
97 }
98
99 @Nullable
100 @Override
101 public ClassNode getClassNode(String name) {
102 return nodeCache.computeIfAbsent(name, (n) -> {
103 byte[] bytes = classBytes.get(name);
104 if (bytes == null) {
105 return null;
106 }
107
108 ClassReader reader = new ClassReader(bytes);
109 ClassNode node = new ClassNode();
110
111 LocalVariableFixVisitor visitor = new LocalVariableFixVisitor(Opcodes.ASM5, node);
112 reader.accept(visitor, 0);
113
114 return node;
115 });
116 }
117
118 public List<ClassEntry> getClassEntries() {
119 List<ClassEntry> entries = new ArrayList<>(classBytes.size());
120 for (String s : classBytes.keySet()) {
121 entries.add(new ClassEntry(s));
122 }
123 return entries;
124 }
125
126 public Map<String, byte[]> getClassDataMap() {
127 return classBytes;
128 }
129}
diff --git a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
index fd4e618..300425b 100644
--- a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
+++ b/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
@@ -13,7 +13,8 @@ package cuchaz.enigma.analysis.index;
13 13
14import com.google.common.collect.HashMultimap; 14import com.google.common.collect.HashMultimap;
15import com.google.common.collect.Multimap; 15import com.google.common.collect.Multimap;
16import cuchaz.enigma.analysis.ParsedJar; 16import cuchaz.enigma.ProgressListener;
17import cuchaz.enigma.analysis.ClassCache;
17import cuchaz.enigma.translation.mapping.EntryResolver; 18import cuchaz.enigma.translation.mapping.EntryResolver;
18import cuchaz.enigma.translation.mapping.IndexEntryResolver; 19import cuchaz.enigma.translation.mapping.IndexEntryResolver;
19import cuchaz.enigma.translation.representation.Lambda; 20import cuchaz.enigma.translation.representation.Lambda;
@@ -23,7 +24,6 @@ import org.objectweb.asm.Opcodes;
23 24
24import java.util.Arrays; 25import java.util.Arrays;
25import java.util.Collection; 26import java.util.Collection;
26import java.util.function.Consumer;
27 27
28public class JarIndex implements JarIndexer { 28public class JarIndex implements JarIndexer {
29 private final EntryIndex entryIndex; 29 private final EntryIndex entryIndex;
@@ -56,23 +56,25 @@ public class JarIndex implements JarIndexer {
56 return new JarIndex(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex, packageVisibilityIndex); 56 return new JarIndex(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex, packageVisibilityIndex);
57 } 57 }
58 58
59 public void indexJar(ParsedJar jar, Consumer<String> progress) { 59 public void indexJar(ClassCache classCache, ProgressListener progress) {
60 progress.accept("Indexing entries (1/4)"); 60 progress.init(4, "Indexing jar");
61 jar.visitReader(name -> new IndexClassVisitor(this, Opcodes.ASM5), ClassReader.SKIP_CODE);
62 61
63 progress.accept("Indexing entry references (2/4)"); 62 progress.step(1, "Entries");
64 jar.visitReader(name -> new IndexReferenceVisitor(this, Opcodes.ASM5), ClassReader.SKIP_FRAMES); 63 classCache.visit(() -> new IndexClassVisitor(this, Opcodes.ASM5), ClassReader.SKIP_CODE);
65 64
66 progress.accept("Finding bridge methods (3/4)"); 65 progress.step(2, "Entry references");
66 classCache.visit(() -> new IndexReferenceVisitor(this, Opcodes.ASM5), ClassReader.SKIP_FRAMES);
67
68 progress.step(3, "Bridge methods");
67 bridgeMethodIndex.findBridgeMethods(); 69 bridgeMethodIndex.findBridgeMethods();
68 70
69 progress.accept("Processing index (4/4)"); 71 progress.step(4, "Processing");
70 processIndex(this); 72 processIndex(this);
71 } 73 }
72 74
73 @Override 75 @Override
74 public void processIndex(JarIndex index) { 76 public void processIndex(JarIndex index) {
75 indexers.forEach(indexer -> indexer.processIndex(index)); 77 indexers.parallelStream().forEach(indexer -> indexer.processIndex(index));
76 } 78 }
77 79
78 @Override 80 @Override