diff options
| author | 2021-07-03 05:34:39 -0500 | |
|---|---|---|
| committer | 2021-07-03 11:34:39 +0100 | |
| commit | 6046e132892c55081229b795f9ba68d32b681d82 (patch) | |
| tree | 139313c7d2292c86e9a7f1b08c354e09a5736b40 /enigma/src/main/java | |
| parent | Revert to shadow 5.2.0 for now because it breaks builds (diff) | |
| download | enigma-fork-6046e132892c55081229b795f9ba68d32b681d82.tar.gz enigma-fork-6046e132892c55081229b795f9ba68d32b681d82.tar.xz enigma-fork-6046e132892c55081229b795f9ba68d32b681d82.zip | |
Update cfr and fixes a few related issues (#414)
* Update cfr and fixes a few related issues
fixes #368 context for token references, missing some field and method
references
* Prevent crash when cfr fails to decompile a lambda and creates a fallback
Signed-off-by: liach <liach@users.noreply.github.com>
* Fix issue with parameters incorrectly spilling into other methods
Signed-off-by: liach <liach@users.noreply.github.com>
* try improve performance of cfr source
Co-authored-by: liach <liach@users.noreply.github.com>
Diffstat (limited to 'enigma/src/main/java')
3 files changed, 50 insertions, 29 deletions
diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java index ffc4788..91fd5a2 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java +++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java | |||
| @@ -24,7 +24,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; | |||
| 24 | import org.objectweb.asm.tree.ClassNode; | 24 | import org.objectweb.asm.tree.ClassNode; |
| 25 | 25 | ||
| 26 | import java.util.Collection; | 26 | import java.util.Collection; |
| 27 | import java.util.HashMap; | ||
| 28 | import java.util.Map; | 27 | import java.util.Map; |
| 29 | 28 | ||
| 30 | public class CfrDecompiler implements Decompiler { | 29 | public class CfrDecompiler implements Decompiler { |
| @@ -33,7 +32,7 @@ public class CfrDecompiler implements Decompiler { | |||
| 33 | private final SourceSettings settings; | 32 | private final SourceSettings settings; |
| 34 | 33 | ||
| 35 | public CfrDecompiler(ClassProvider classProvider, SourceSettings sourceSettings) { | 34 | public CfrDecompiler(ClassProvider classProvider, SourceSettings sourceSettings) { |
| 36 | Map<String, String> options = new HashMap<>(); | 35 | Map<String, String> options = Map.of("trackbytecodeloc", "true"); |
| 37 | 36 | ||
| 38 | state = new DCCommonState(OptionsImpl.getFactory().create(options), new ClassFileSource2() { | 37 | state = new DCCommonState(OptionsImpl.getFactory().create(options), new ClassFileSource2() { |
| 39 | @Override | 38 | @Override |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java index ba831d7..7c63afc 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java +++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java | |||
| @@ -13,11 +13,12 @@ import org.checkerframework.checker.nullness.qual.Nullable; | |||
| 13 | public class CfrSource implements Source { | 13 | public class CfrSource implements Source { |
| 14 | private final SourceSettings settings; | 14 | private final SourceSettings settings; |
| 15 | private final ClassFile tree; | 15 | private final ClassFile tree; |
| 16 | private final SourceIndex index; | ||
| 17 | private final String string; | ||
| 18 | private final DCCommonState state; | 16 | private final DCCommonState state; |
| 19 | private final TypeUsageInformation typeUsage; | 17 | private final TypeUsageInformation typeUsage; |
| 20 | private final Options options; | 18 | private final Options options; |
| 19 | private final EntryRemapper mapper; | ||
| 20 | |||
| 21 | private SourceIndex index; | ||
| 21 | 22 | ||
| 22 | public CfrSource(SourceSettings settings, ClassFile tree, DCCommonState state, TypeUsageInformation typeUsage, Options options, @Nullable EntryRemapper mapper) { | 23 | public CfrSource(SourceSettings settings, ClassFile tree, DCCommonState state, TypeUsageInformation typeUsage, Options options, @Nullable EntryRemapper mapper) { |
| 23 | this.settings = settings; | 24 | this.settings = settings; |
| @@ -25,16 +26,7 @@ public class CfrSource implements Source { | |||
| 25 | this.state = state; | 26 | this.state = state; |
| 26 | this.typeUsage = typeUsage; | 27 | this.typeUsage = typeUsage; |
| 27 | this.options = options; | 28 | this.options = options; |
| 28 | 29 | this.mapper = mapper; | |
| 29 | EnigmaDumper dumper = new EnigmaDumper(new StringBuilder(), settings, typeUsage, options, mapper); | ||
| 30 | tree.dump(state.getObfuscationMapping().wrap(dumper)); | ||
| 31 | index = dumper.getIndex(); | ||
| 32 | string = dumper.getString(); | ||
| 33 | } | ||
| 34 | |||
| 35 | @Override | ||
| 36 | public String asString() { | ||
| 37 | return string; | ||
| 38 | } | 30 | } |
| 39 | 31 | ||
| 40 | @Override | 32 | @Override |
| @@ -44,6 +36,23 @@ public class CfrSource implements Source { | |||
| 44 | 36 | ||
| 45 | @Override | 37 | @Override |
| 46 | public SourceIndex index() { | 38 | public SourceIndex index() { |
| 39 | ensureDecompiled(); | ||
| 47 | return index; | 40 | return index; |
| 48 | } | 41 | } |
| 42 | |||
| 43 | @Override | ||
| 44 | public String asString() { | ||
| 45 | ensureDecompiled(); | ||
| 46 | return index.getSource(); | ||
| 47 | } | ||
| 48 | |||
| 49 | private synchronized void ensureDecompiled() { | ||
| 50 | if (index != null) { | ||
| 51 | return; | ||
| 52 | } | ||
| 53 | |||
| 54 | EnigmaDumper dumper = new EnigmaDumper(new StringBuilder(), settings, typeUsage, options, mapper); | ||
| 55 | tree.dump(state.getObfuscationMapping().wrap(dumper)); | ||
| 56 | index = dumper.getIndex(); | ||
| 57 | } | ||
| 49 | } | 58 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java index d0734c5..b85851f 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java +++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java | |||
| @@ -12,17 +12,16 @@ import cuchaz.enigma.translation.representation.entry.Entry; | |||
| 12 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 12 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 13 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | 13 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; |
| 14 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 14 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 15 | import org.benf.cfr.reader.bytecode.analysis.types.JavaArrayTypeInstance; | 15 | import org.benf.cfr.reader.bytecode.analysis.loc.HasByteCodeLoc; |
| 16 | import org.benf.cfr.reader.bytecode.analysis.types.JavaGenericBaseInstance; | ||
| 17 | import org.benf.cfr.reader.bytecode.analysis.types.JavaRefTypeInstance; | 16 | import org.benf.cfr.reader.bytecode.analysis.types.JavaRefTypeInstance; |
| 18 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; | 17 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; |
| 19 | import org.benf.cfr.reader.bytecode.analysis.types.MethodPrototype; | 18 | import org.benf.cfr.reader.bytecode.analysis.types.MethodPrototype; |
| 20 | import org.benf.cfr.reader.bytecode.analysis.types.RawJavaType; | ||
| 21 | import org.benf.cfr.reader.bytecode.analysis.variables.NamedVariable; | 19 | import org.benf.cfr.reader.bytecode.analysis.variables.NamedVariable; |
| 22 | import org.benf.cfr.reader.entities.AccessFlag; | 20 | import org.benf.cfr.reader.entities.AccessFlag; |
| 23 | import org.benf.cfr.reader.entities.ClassFile; | 21 | import org.benf.cfr.reader.entities.ClassFile; |
| 24 | import org.benf.cfr.reader.entities.ClassFileField; | 22 | import org.benf.cfr.reader.entities.ClassFileField; |
| 25 | import org.benf.cfr.reader.entities.Field; | 23 | import org.benf.cfr.reader.entities.Field; |
| 24 | import org.benf.cfr.reader.entities.Method; | ||
| 26 | import org.benf.cfr.reader.state.TypeUsageInformation; | 25 | import org.benf.cfr.reader.state.TypeUsageInformation; |
| 27 | import org.benf.cfr.reader.util.getopt.Options; | 26 | import org.benf.cfr.reader.util.getopt.Options; |
| 28 | import org.benf.cfr.reader.util.output.Dumper; | 27 | import org.benf.cfr.reader.util.output.Dumper; |
| @@ -49,6 +48,7 @@ public class EnigmaDumper extends StringStreamDumper { | |||
| 49 | private final TypeUsageInformation typeUsage; | 48 | private final TypeUsageInformation typeUsage; |
| 50 | private final MovableDumperContext dumperContext; | 49 | private final MovableDumperContext dumperContext; |
| 51 | private boolean muteLine = false; | 50 | private boolean muteLine = false; |
| 51 | private MethodEntry contextMethod = null; | ||
| 52 | 52 | ||
| 53 | public EnigmaDumper(StringBuilder sb, SourceSettings sourceSettings, TypeUsageInformation typeUsage, Options options, | 53 | public EnigmaDumper(StringBuilder sb, SourceSettings sourceSettings, TypeUsageInformation typeUsage, Options options, |
| 54 | @Nullable EntryRemapper mapper) { | 54 | @Nullable EntryRemapper mapper) { |
| @@ -68,18 +68,19 @@ public class EnigmaDumper extends StringStreamDumper { | |||
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | private MethodEntry getMethodEntry(MethodPrototype method) { | 70 | private MethodEntry getMethodEntry(MethodPrototype method) { |
| 71 | if (method == null || method.getClassType() == null) { | 71 | if (method == null || method.getOwner() == null) { |
| 72 | return null; | 72 | return null; |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | MethodDescriptor desc = new MethodDescriptor(method.getOriginalDescriptor()); | 75 | MethodDescriptor desc = new MethodDescriptor(method.getOriginalDescriptor()); |
| 76 | 76 | ||
| 77 | return new MethodEntry(getClassEntry(method.getClassType()), method.getName(), desc); | 77 | return new MethodEntry(getClassEntry(method.getOwner()), method.getName(), desc); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | private LocalVariableEntry getParameterEntry(MethodPrototype method, int parameterIndex, String name) { | 80 | private LocalVariableEntry getParameterEntry(MethodPrototype method, int parameterIndex, String name) { |
| 81 | MethodEntry owner = getMethodEntry(method); | 81 | MethodEntry owner = getMethodEntry(method); |
| 82 | if (owner == null) { | 82 | // params may be not computed if cfr creates a lambda expression fallback, e.g. in PointOfInterestSet |
| 83 | if (owner == null || !method.parametersComputed()) { | ||
| 83 | return null; | 84 | return null; |
| 84 | } | 85 | } |
| 85 | 86 | ||
| @@ -253,7 +254,7 @@ public class EnigmaDumper extends StringStreamDumper { | |||
| 253 | if (defines) { | 254 | if (defines) { |
| 254 | index.addDeclaration(token, entry); // override as cfr reuses local vars | 255 | index.addDeclaration(token, entry); // override as cfr reuses local vars |
| 255 | } else { | 256 | } else { |
| 256 | index.addReference(token, entry, null); | 257 | index.addReference(token, entry, contextMethod); |
| 257 | } | 258 | } |
| 258 | } | 259 | } |
| 259 | 260 | ||
| @@ -276,7 +277,7 @@ public class EnigmaDumper extends StringStreamDumper { | |||
| 276 | if (defines) { | 277 | if (defines) { |
| 277 | this.index.addDeclaration(token, entry); | 278 | this.index.addDeclaration(token, entry); |
| 278 | } else { | 279 | } else { |
| 279 | this.index.addReference(token, entry, null); | 280 | this.index.addReference(token, entry, contextMethod); |
| 280 | } | 281 | } |
| 281 | } | 282 | } |
| 282 | 283 | ||
| @@ -293,27 +294,31 @@ public class EnigmaDumper extends StringStreamDumper { | |||
| 293 | public Dumper identifier(String name, Object ref, boolean defines) { | 294 | public Dumper identifier(String name, Object ref, boolean defines) { |
| 294 | super.identifier(name, ref, defines); | 295 | super.identifier(name, ref, defines); |
| 295 | Entry<?> entry; | 296 | Entry<?> entry; |
| 297 | if (defines) { | ||
| 298 | refs.remove(ref); | ||
| 299 | return this; | ||
| 300 | } | ||
| 296 | if ((entry = refs.get(ref)) == null) { | 301 | if ((entry = refs.get(ref)) == null) { |
| 297 | return this; | 302 | return this; |
| 298 | } | 303 | } |
| 299 | int now = sb.length(); | 304 | int now = sb.length(); |
| 300 | Token token = new Token(now - name.length(), now, name); | 305 | Token token = new Token(now - name.length(), now, name); |
| 301 | index.addReference(token, entry, null); | 306 | index.addReference(token, entry, contextMethod); |
| 302 | return this; | 307 | return this; |
| 303 | } | 308 | } |
| 304 | 309 | ||
| 305 | @Override | 310 | @Override |
| 306 | public Dumper fieldName(String name, Field field, JavaTypeInstance owner, boolean hiddenDeclaration, boolean defines) { | 311 | public Dumper fieldName(String name, String descriptor, JavaTypeInstance owner, boolean hiddenDeclaration, boolean isStatic, boolean defines) { |
| 307 | super.fieldName(name, field, owner, hiddenDeclaration, defines); | 312 | super.fieldName(name, descriptor, owner, hiddenDeclaration, isStatic, defines); |
| 308 | int now = sb.length(); | 313 | int now = sb.length(); |
| 309 | Token token = new Token(now - name.length(), now, name); | 314 | Token token = new Token(now - name.length(), now, name); |
| 310 | Entry<?> entry = field == null ? null : getFieldEntry(owner, name, field.getDescriptor()); | 315 | if (descriptor != null) { |
| 316 | Entry<?> entry = getFieldEntry(owner, name, descriptor); | ||
| 311 | 317 | ||
| 312 | if (entry != null) { | ||
| 313 | if (defines) { | 318 | if (defines) { |
| 314 | index.addDeclaration(token, entry); | 319 | index.addDeclaration(token, entry); |
| 315 | } else { | 320 | } else { |
| 316 | index.addReference(token, entry, null); | 321 | index.addReference(token, entry, contextMethod); |
| 317 | } | 322 | } |
| 318 | } | 323 | } |
| 319 | 324 | ||
| @@ -348,7 +353,7 @@ public class EnigmaDumper extends StringStreamDumper { | |||
| 348 | if (defines) { | 353 | if (defines) { |
| 349 | index.addDeclaration(token, getClassEntry(type)); | 354 | index.addDeclaration(token, getClassEntry(type)); |
| 350 | } else { | 355 | } else { |
| 351 | index.addReference(token, getClassEntry(type), null); | 356 | index.addReference(token, getClassEntry(type), contextMethod); |
| 352 | } | 357 | } |
| 353 | return; | 358 | return; |
| 354 | } | 359 | } |
| @@ -367,6 +372,14 @@ public class EnigmaDumper extends StringStreamDumper { | |||
| 367 | return new EnigmaDumper(this.sb, sourceSettings, innerclassTypeUsageInformation, options, mapper, index, dumperContext); | 372 | return new EnigmaDumper(this.sb, sourceSettings, innerclassTypeUsageInformation, options, mapper, index, dumperContext); |
| 368 | } | 373 | } |
| 369 | 374 | ||
| 375 | @Override | ||
| 376 | public void informBytecodeLoc(HasByteCodeLoc loc) { | ||
| 377 | Collection<Method> methods = loc.getLoc().getMethods(); | ||
| 378 | if (!methods.isEmpty()) { | ||
| 379 | this.contextMethod = getMethodEntry(methods.iterator().next().getMethodPrototype()); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 370 | public SourceIndex getIndex() { | 383 | public SourceIndex getIndex() { |
| 371 | index.setSource(getString()); | 384 | index.setSource(getString()); |
| 372 | return index; | 385 | return index; |