diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/main/java/com/falsepattern/lib/internal/asm/transformers/MixinPluginTransformer.java b/src/main/java/com/falsepattern/lib/internal/asm/transformers/MixinPluginTransformer.java index efe179f..c27f2bc 100644 --- a/src/main/java/com/falsepattern/lib/internal/asm/transformers/MixinPluginTransformer.java +++ b/src/main/java/com/falsepattern/lib/internal/asm/transformers/MixinPluginTransformer.java @@ -23,6 +23,7 @@ package com.falsepattern.lib.internal.asm.transformers; import com.falsepattern.lib.internal.Tags; +import com.falsepattern.lib.turboasm.ClassHeaderMetadata; import com.falsepattern.lib.turboasm.ClassNodeHandle; import com.falsepattern.lib.turboasm.TurboClassTransformer; import lombok.val; @@ -75,17 +76,11 @@ public class MixinPluginTransformer implements TurboClassTransformer { if (!classNode.isPresent()) return false; - if (classNode.isOriginal()) { - val meta = classNode.getOriginalMetadata(); - if (meta != null && meta.interfacesCount == 0) - return false; - } - - val cn = classNode.getNode(); - if (cn == null) + ClassHeaderMetadata metadata = classNode.getOriginalMetadata(); + if (metadata == null) return false; - for (String i : cn.interfaces) { + for (String i : metadata.binaryInterfaceNames()) { if (IMIXINPLUGIN_INTERNAL.equals(i) || IMIXINCONFIGPLUGIN_INTERNAL.equals(i)) { return true; } diff --git a/src/main/java/com/falsepattern/lib/turboasm/ClassHeaderMetadata.java b/src/main/java/com/falsepattern/lib/turboasm/ClassHeaderMetadata.java index 103bc6b..44319aa 100644 --- a/src/main/java/com/falsepattern/lib/turboasm/ClassHeaderMetadata.java +++ b/src/main/java/com/falsepattern/lib/turboasm/ClassHeaderMetadata.java @@ -30,6 +30,9 @@ import org.objectweb.asm.Opcodes; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * Utilities for quickly processing class files without fully parsing them. @@ -49,8 +52,11 @@ public final class ClassHeaderMetadata implements FastClassAccessor { public final int thisClassIndex; public final int superClassIndex; public final int interfacesCount; + public final int @NotNull [] interfaceIndices; public final @NotNull String binaryThisName; public final @Nullable String binarySuperName; + /** List is unmodifiable */ + public final @NotNull List<@NotNull String> binaryInterfaceNames; /** * Attempts to parse a class header. @@ -88,6 +94,9 @@ public final class ClassHeaderMetadata implements FastClassAccessor { this.thisClassIndex = u16(bytes, cpOff + Offsets.pastCpThisClassU16); this.superClassIndex = u16(bytes, cpOff + Offsets.pastCpSuperClassU16); this.interfacesCount = u16(bytes, cpOff + Offsets.pastCpInterfacesCountU16); + this.interfaceIndices = new int[this.interfacesCount]; + List interfaceNames = new ArrayList<>(this.interfacesCount); + // Parse this&super names if (constantPoolEntryTypes[thisClassIndex - 1] != ConstantPoolEntryTypes.Class) { throw new IllegalArgumentException("This class index is not a class ref"); @@ -110,6 +119,25 @@ public final class ClassHeaderMetadata implements FastClassAccessor { } this.binarySuperName = modifiedUtf8(bytes, constantPoolEntryOffsets[superNameIndex - 1] + 1); } + + // Parse interface names + for (int i = 0; i < this.interfacesCount; i++) { + final int interfaceOffset = cpOff + Offsets.pastCpInterfacesList + i * 2; + final int interfaceIndex = u16(bytes, interfaceOffset); + if (constantPoolEntryTypes[interfaceIndex - 1] != ConstantPoolEntryTypes.Class) { + throw new IllegalArgumentException("Interface " + i + " index is not a class ref"); + } + final int interfaceNameIndex = u16(bytes, constantPoolEntryOffsets[interfaceIndex - 1] + 1); + if (constantPoolEntryTypes[interfaceNameIndex - 1] != ConstantPoolEntryTypes.Utf8) { + throw new IllegalArgumentException("Interface " + i + " index does not point to a UTF8 entry"); + } + final String binaryInterfaceName = + modifiedUtf8(bytes, constantPoolEntryOffsets[interfaceNameIndex - 1] + 1); + + this.interfaceIndices[i] = interfaceIndex; + interfaceNames.add(binaryInterfaceName); + } + this.binaryInterfaceNames = Collections.unmodifiableList(interfaceNames); } /** Helpers to read big-endian values from class files. */ @@ -189,6 +217,8 @@ public final class ClassHeaderMetadata implements FastClassAccessor { public static final int pastCpSuperClassU16 = pastCpThisClassU16 + 2; /** The value of the interfaces_count item gives the number of direct superinterfaces of this class or interface type */ public static final int pastCpInterfacesCountU16 = pastCpSuperClassU16 + 2; + + public static final int pastCpInterfacesList = pastCpInterfacesCountU16 + 2; } public enum ConstantPoolEntryTypes { @@ -354,4 +384,9 @@ public final class ClassHeaderMetadata implements FastClassAccessor { public @Nullable String binarySuperName() { return binarySuperName; } -} \ No newline at end of file + + @Override + public @NotNull List<@NotNull String> binaryInterfaceNames() { + return binaryInterfaceNames; + } +} diff --git a/src/main/java/com/falsepattern/lib/turboasm/FastClassAccessor.java b/src/main/java/com/falsepattern/lib/turboasm/FastClassAccessor.java index 49ca1f7..e79cceb 100644 --- a/src/main/java/com/falsepattern/lib/turboasm/FastClassAccessor.java +++ b/src/main/java/com/falsepattern/lib/turboasm/FastClassAccessor.java @@ -28,6 +28,9 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** An accessor to metadata about a class that is quickly accessible without fully parsing one. */ public interface FastClassAccessor { @@ -51,6 +54,9 @@ public interface FastClassAccessor { /** Binary (slash-separated packages) name of the super-class, null for the Object class */ @Nullable String binarySuperName(); + /** Binary (slash-separated packages) names of the implemented interfaces, list is unmodifiable */ + @NotNull + List<@NotNull String> binaryInterfaceNames(); static OfLoaded ofLoaded(Class loadedClass) { return new OfLoaded(loadedClass); @@ -111,10 +117,18 @@ public interface FastClassAccessor { public @Nullable String binarySuperName() { return handle.superName; } + + @Override + public @NotNull List<@NotNull String> binaryInterfaceNames() { + return handle.interfaces == null + ? Collections.emptyList() + : Collections.unmodifiableList(handle.interfaces); + } } final class OfLoaded implements FastClassAccessor { public final Class handle; + private @Nullable List<@NotNull String> interfacesCache = null; private OfLoaded(Class handle) { this.handle = handle; @@ -165,5 +179,20 @@ public interface FastClassAccessor { final Class superclass = handle.getSuperclass(); return superclass == null ? null : superclass.getName().replace('.', '/'); } + + @Override + public @NotNull List<@NotNull String> binaryInterfaceNames() { + if (interfacesCache != null) { + return interfacesCache; + } + + Class[] interfaces = handle.getInterfaces(); + List binaryInterfaceNames = new ArrayList<>(interfaces.length); + for (Class iface : interfaces) { + binaryInterfaceNames.add(iface.getName().replace('.', '/')); + } + interfacesCache = Collections.unmodifiableList(binaryInterfaceNames); + return interfacesCache; + } } -} \ No newline at end of file +}