diff --git a/deob/src/main/java/dev/openrs2/deob/transform/InvokeSpecialTransformer.kt b/deob/src/main/java/dev/openrs2/deob/transform/InvokeSpecialTransformer.kt index 64db8e94..194bae90 100644 --- a/deob/src/main/java/dev/openrs2/deob/transform/InvokeSpecialTransformer.kt +++ b/deob/src/main/java/dev/openrs2/deob/transform/InvokeSpecialTransformer.kt @@ -9,6 +9,44 @@ import org.objectweb.asm.tree.ClassNode import org.objectweb.asm.tree.MethodInsnNode import org.objectweb.asm.tree.MethodNode +/** + * A [Transformer] that replaces `INVOKESPECIAL` instructions in static methods + * with `INVOKEVIRTUAL` equivalents. + * + * The client contains some methods in `final` classes that use `INVOKESPECIAL` + * to invoke non-`` methods on objects of exactly the same type as the + * containing class. Furthermore, these `INVOKESPECIAL` instructions are + * sometimes present in `static` methods. + * + * As the containing class is `final` and as the method reference is not a + * superclass of the containing class, these calls actually end up being + * treated in the exact same way as an `INVOKEVIRTRUAL` call. + * + * While these calls are unusual (and probably never generated by a standard + * Java compiler, as there is no way to express them in Java source code), they + * are permitted by the + * [JVM specification](https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html#jvms-6.5.invokespecial). + * + * It is likely that this unusual use of `INVOKESPECIAL` is an optimization + * (`INVOKESPECIAL` was originally used as a more generic `INVOKENONVIRTUAL` + * instruction, and non-virtual function calls are cheaper than virtual + * function calls) or an obfuscation technique. + * + * The [StaticScramblingTransformer] moves static methods containing these + * `INVOKESPECIAL` instructions to new classes. This change is still permitted + * by the JVM specification, which does not place any restrictions on the class + * referenced by the `INVOKESPECIAL` instruction. + * + * However, the + * [verifier](https://github.com/openjdk/jdk11u/blob/3789983e89c9de252ef546a1b98a732a7d066650/src/java.base/share/native/libverify/check_code.c#L1342) + * in modern JVMs is stricter and considers non-`` `INVOKESPECIAL` + * instructions referencing classes that are not the containing class or its + * direct superclass illegal. + * + * This transformer replaces `INVOKESPECIAL` with equivalent `INVOKEVIRTUAL` + * instructions where possible, allowing the [StaticScramblingTransformer] to + * produce verifiable output. + */ class InvokeSpecialTransformer : Transformer() { private var invokeSpecialsReplaced = 0