|
|
|
@ -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-`<init>` 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-`<init>` `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 |
|
|
|
|
|
|
|
|
|