Class.forName Bytecode Transformation Investigation
Sonia Zaldana Calles
szaldana at redhat.com
Wed Sep 28 15:51:55 UTC 2022
Hi folks,
In line with Dan’s previous investigation on bytecode transformations to
modify Java’s dynamic behaviour, I have created a ClassForName JLink Plugin
which translates the reflective operation Class.forName
<https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#forName-java.lang.String->
to the ldc bytecode instruction using the ASM <https://asm.ow2.io/>
library.
The bytecode transformation switches out calls to Class.forName to ldc
instructions for classes that are statically known, along with addressing
the mismatch between Class.forName, which initialises the class by default,
and ldc, which does not, by using MethodHandles.Lookup.ensureInitialized
<https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html#ensureInitialized(java.lang.Class)>
.
For example, the bytecode sequence
Class.forName(“com.sonia.hello.HelloWorld”) is transformed as shown below:
Original:
0: ldc #7 // String com.sonia.hello.HelloWorld
2: invokestatic #9 // Method
java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
Transformed:
0: invokestatic #43 // Method
java/lang/invoke/MethodHandles.lookup:()Ljava/lang/invoke/MethodHandles$Lookup;
3: ldc #45 // class com/sonia/hello/HelloWorld
5: invokevirtual #51 // Method
java/lang/invoke/MethodHandles$Lookup.ensureInitialized:(Ljava/lang/Class;)Ljava/lang/Class;
The plugin supports configuring two modes: global and module-aware. The
module mode transforms Class.forName calls only when accessing a class
accessible to the current module per the module graph, while the global
mode transforms all classes regardless of readability. Note, class
accessibility is determined per the JVMS 5.4.4
<http://cr.openjdk.java.net/~iris/se/18/latestSpec/java-se-18-jvms-fr-diffs.pdf>
- a class must be public, its module must be read by the current class’s
module and its package must be exported to the current class’s module.
There are slight differences between the language’s and the VM’s view of
accessibility.
We have also introduced an internal plugin called ModuleGraphPlugin which
creates a single logical view of the module graph. This plugin separates
the logic determining class readability and is queried by the ClassForName
plugin to drive transformations. It doesn’t require further configuration
from users as it is configured by default when using the ClassForName
plugin.
The ModuleGraphPlugin was separated out as it allows other plugins to share
a common view of the module graph without needing to have each plugin
process the module-info.java files.
While a Class.forName JLink plugin previously existed (and was removed), it
was limited to modifications within a module as it didn’t have the
ModuleGraphPlugin-awareness of the full module graph.
We don’t expect any performance improvement from this change itself, but we
are expecting it to increase the ability of other future plugins to reason
about application behaviour and to potentially help remove reflective
operations in other contexts.
Find below the GitHub link with the changes:
https://github.com/SoniaZaldana/jdk-sandbox/tree/classforname-plugin
Thanks,
Sonia
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/leyden-dev/attachments/20220928/63567028/attachment.htm>
More information about the leyden-dev
mailing list