1

最近、低レベルの Java を使用して、JVM バイトコードを変更し、.java ファイルをコンパイルせずにクラス ファイルを生成しています。について知ったばかりで、独自の JVM バイトコード ツールを使用して独自の定数と属性をinvokedynamic生成し、適切に使用できるようにすることができました。InvokeDynamicBootstrapMethodinvokedynamic

この後、同じメソッドで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

4

0 に答える 0