最近、低レベルの Java を使用して、JVM バイトコードを変更し、.java ファイルをコンパイルせずにクラス ファイルを生成しています。について知ったばかりで、独自の JVM バイトコード ツールを使用して独自の定数と属性をinvokedynamic
生成し、適切に使用できるようにすることができました。InvokeDynamic
BootstrapMethod
invokedynamic
この後、同じメソッドでinvokestatic
との両方をテストする簡単なタイミング スクリプトを Java で作成しました。invokedynamic
しかし、私のスクリプトは、それinvokedynamic
が より約 8% 高速でinvokestatic
あることを示しました。
各メソッドの時間を測定するために使用したコードは次のとおりです。
import java.lang.invoke.*;
public class InvokeDynamicTest implements Runnable {
private static void doNothing(){
//do nothing
}
private static CallSite getCallSite(MethodHandles.Lookup s, String name, MethodType methodType){
try{
return new ConstantCallSite(s.findStatic(InvokeDynamicTest.class, name, methodType));
}catch(Throwable t){
throw new RuntimeException(t);
}
}
public static void main(String[] args) {
final Runnable r = (Runnable) new InvokeDynamicTest();
long time = System.currentTimeMillis();
int counter = 0;
while(System.currentTimeMillis() - time < 5000){
doNothing();
counter++;
}
System.out.println(counter);
time = System.currentTimeMillis();
counter = 0;
while(System.currentTimeMillis() - time < 5000){
r.run();
counter++;
}
System.out.println(counter);
}
public void run() {
//Use bytecode modifier to insert invokedynamic
}
}
出力は次のとおりです。
514048300
545970671
コンパイル後に変更されたバイトコードに関しては、次のように新しい定数がダンプされjavap
ます。
#9 = Class #10 // InvokeDynamicTest
#10 = Utf8 InvokeDynamicTest
...
#70 = Utf8 getCallSite
#71 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#72 = NameAndType #70:#71 // getCallSite:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#73 = Methodref #9.#72 // InvokeDynamicTest.getCallSite:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#74 = MethodHandle 6:#73 // REF_invokeStatic InvokeDynamicTest.getCallSite:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#75 = Utf8 doNothing
#76 = Utf8 ()V
#77 = NameAndType #75:#76 // doNothing:()V
#78 = InvokeDynamic #0:#77 // #0:doNothing:()V
run
メソッドの新しいコードは次のとおりです。
public void run();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=100, locals=100, args_size=1
0: invokedynamic #78, 0 // InvokeDynamic #0:doNothing:()V
5: return
ここにBootstrapMethods
表があります:
BootstrapMethods:
0: #74 REF_invokeStatic InvokeDynamicTest.getCallSite:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
何か不足していますか?どうinvokedynamic
すればより速くなるかわかりませんinvokestatic