2012-05-02 11 views
16

今日のJVMでJava仮想マシンのオペコードNOPが実際に使用されていますか?その場合、NOPがバイトコードで生成されるシナリオは何ですか?JVMバイトコードのNOPとは何ですか?

私は、NOPでバイトコードにコンパイルするJavaコードの例を見ることにも興味があります。


更新

コードを生成しながらBCELのMethodGenクラスはNOP操作を挿入する必要があるかもしれない、

を言います。

他のバイトコード生成ライブラリは、受け入れられた答えで指摘されているのと同じボートにあると推測しています。

+0

通常、デバッグコードでは、 '{'のようにバイトコードに変換されないものにブレークポイントを許可するために使用されます。 – vcsjones

+0

Javaファイルが 'javac -g'でコンパイルされているときに、これがバイトコードに現れることを意味しますか? – jbranchaud

+0

私は 'javac'がそれをするとは思わない。しかし、他のコンパイラやデバッガでもその機能を利用することができます。 – vcsjones

答えて

12

一部NOPバイトコードのユースケースは、classファイル変換、最適化およびツールによって実行される静的解析のためのものなど解析と最適化の目的のためにNOPのいくつかの使用上のApache BCEL manualタッチApache BCELASMFindBugsPMD、など。

JVMは、同期セーフポイントにあるコードブロックがfalse sharingを避けるように正しく整列されるように、JIT最適化のためにNOPバイトコードを使用することがあります。

NOPのバイトコードを含むJDK javacコンパイラを使用してコンパイルされたサンプルコードは、興味深い課題です。しかし、the bytecode instruction stream is only single-byte aligned以降、NOPのバイトコードを含むclassファイルがコンパイラによって生成されるのではないかと疑います。私はそのような例を見るのが好奇妙だが、私は自分自身を考えることはできない。ここ

1

多くの場合、プロセッサパイプラインの最適化のためにopsは追加されません。私はJavaが現在それらをどの程度使用しているのか分かりません。 Wikipediaから

A NOPは、最も一般的には、分岐遅延スロットを占有する、危険を防止するために、メモリ アライメントを強制するために、タイミングの目的に使用される、または プレースホルダとして交換します後でプログラム の開発中のアクティブな指示(またはリファクタリング時に削除された命令を置き換えて に問題や時間がかかる)いくつかのケースでは、NOPは軽微な副作用を持つことがあります。 例えばモトローラ68000シリーズのプロセッサでは、 のNOPオペコードがパイプラインの同期化を引き起こす。

+6

これは物理マシンのオペコードでは意味がありますが、*バーチャルマシンのオペコードには何が使われますか? –

+0

私は答えを感謝しますが、この質問は非常に具体的にJVMについてです。 – jbranchaud

2

は私が働いてきたいくつかのコードの例である(Eclipse用のバイトコードビジュアライザから見て)バイトコードに入れNOP命令

オリジナルコード

public abstract class Wrapper<T extends Wrapper<T,E>,E> 
    implements Supplier<Optional<E>>, Consumer<E> 
{ 
    /** The wrapped object. */ 
    protected Optional<E> inner; 

    /* 
    * (non-Javadoc) 
    * @see java.lang.Object#equals(java.lang.Object) 
    */ 
    /** 
    * A basic equals method that will compare the wrapped object to 
    * whatever you throw at it, whether it is wrapped or not. 
    */ 
    @Override 
    public boolean equals(final Object that) 
    { 
    return this==that 
     ||LambdaUtils.castAndMap(that,Wrapper.class,afterCast 
      -> inner.equals(afterCast.inner)) 
     .orElseGet(() 
      -> LambdaUtils.castAndMap(that,Optional.class,afterCast 
       -> inner.equals(afterCast)) 
      .orElseGet(() 
       -> Optional.ofNullable(that).map(thatobj 
        -> that.equals(inner.get())) 
       .orElseGet(() 
        -> false))); 
    } 
} 

equals(Object)メソッドの変換されたバイトコード

public boolean equals(java.lang.Object arg0) { 
    /* L27 */ 
    0 aload_0;    /* this */ 
    1 aload_1;    /* that */ 
    2 if_acmpeq 36; 
    /* L28 */ 
    5 aload_1;    /* that */ 
    6 ldc 1; 
    8 aload_0;    /* this */ 
    9 invokedynamic 29;  /* java.util.function.Function apply(ext.cat.wcutils.collections.Wrapper arg0) */ 
    12 nop; 
    13 nop; 
    14 invokestatic 30;  /* java.util.Optional ext.cat.wcutils.util.LambdaUtils.castAndMap(java.lang.Object arg0, java.lang.Class arg1, java.util.function.Function arg2) */ 
    /* L30 */ 
    17 aload_0;    /* this */ 
    18 aload_1;    /* that */ 
    19 invokedynamic 39;  /* java.util.function.Supplier get(ext.cat.wcutils.collections.Wrapper arg0, java.lang.Object arg1) */ 
    22 nop; 
    23 nop; 
    24 invokevirtual 40;  /* java.lang.Object orElseGet(java.util.function.Supplier arg0) */ 
    27 checkcast 46;   /* java.lang.Boolean */ 
    30 invokevirtual 48;  /* boolean booleanValue() */ 
    /* L37 */ 
    33 ifne 5; 
    /* L27 */ 
    36 iconst_0; 
    37 ireturn; 
    38 iconst_1; 
    39 ireturn; 
} 

なぜそれらが挿入されるのかわかりません。私は彼らがパフォーマンスに悪影響を与えないことを願っています。

+3

'nop'はありません。これはあなたが使用したBytecode Visualizerのバグです。 'invokedynamic'命令は5バイトで構成され、最後の2つは仕様ごとにゼロです。どうやら、バイトコード・ビジュアライザはそのことを知らず、 'invokedynamic'命令が3バイトしか持たないと仮定し、2つのゼロバイトを' nop'命令として誤って解釈します。 [JVM Spec invokedynamic](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokedynamic)を参照してください。 – Holger

+0

私はそれが理にかなっていると思います。 Eclipse NeonのBytecode Visualizerのアップデートを待っています。たぶん私たちは開発者に伝えるべきです。 – HesNotTheStig

関連する問題