Class.forName Bytecode Transformation Investigation

Brian Goetz brian.goetz at oracle.com
Wed Sep 28 16:59:03 UTC 2022


One possible compatibility issue is the exceptions that may be thrown.  
Have we done a review to compare the exceptions thrown by Class::forName 
vs the substituted code?

On 9/28/2022 11:51 AM, Sonia Zaldana Calles wrote:
> 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 
> <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/78499eb2/attachment.htm>


More information about the leyden-dev mailing list