14

Javaが安全な言語であることは知っていますが、行列の計算が必要な場合、もっと速く何かを試すことができますか?

私はC++、Digital-Marsコンパイラ、FASMで__asm{}を学んでいます。Javaでも同じことをしたいです。関数にアセンブリコードをインライン化するにはどうすればよいですか?これも可能ですか?

このようなもの(CPUのAVXサポートを使用して、配列のすべての要素を分岐せずに値にクランプするベクトル化されたループ):

JavaAsmBlock(
   # get pointers into registers somehow
   # and tell Java which registers the asm clobbers somehow
     vbroadcastss  twenty_five(%rip), %ymm0
     xor   %edx,%edx
.Lloop:                            # do {
    vmovups   (%rsi, %rdx, 4), %ymm1
    vcmpltps   %ymm1, %ymm0, %ymm2
    vblendvps  %ymm2, %ymm0, %ymm1, %ymm1  # TODO: use vminps instead
    vmovups    %ymm1, (%rdi, %rdx, 4)
    # TODO: unroll the loop a bit, and maybe handle unaligned output specially if that's common
    add         $32, %rdx
    cmp         %rcx, %rdx
    jb     .Lloop                  # } while(idx < count)
    vzeroupper
);

System.out.println(var[0]);

コードインジェクターを使いたくありません。IntelまたはAT&Tスタイルのx86の説明を見たいです。

4

6 に答える 6

20

Javaコードと基盤となるハードウェアの間には抽象化レイヤーがあり、この種のことは原則として不可能です。同じバイトコードが異なるプロセッサと異なるアーキテクチャで実行される可能性があるため、技術的には、基盤となるマシンでコードがどのように表現されているかを知ることはできません。

公式にできることは、Java Native Interface(JNI)を使用して、Javaコードからネイティブコードを呼び出すことです。呼び出しのオーバーヘッドはかなりのものであり、Javaとのデータ共有にはかなりの費用がかかるため、これは適切なサイズのネイティブコードのチャンクにのみ使用する必要があります。

ただし、理論的には、このような拡張は可能です。特定のプラットフォームを対象とし、アセンブリエスケープを許可したJavaコンパイラを想像することができます。コンパイラはABIを公開する必要があるため、呼び出し規約を知っているはずです。しかし、私はそれを知っていません。ただし、Javaをネイティブコードに直接コンパイルするコンパイラがいくつか あります。それらの1つが、私の知らないうちにこのようなものをサポートしている可能性があります。または、そうするように拡張することもできます。

最後に、まったく別のレベルで、JasminのようなJVM用のバイトコードアセンブラがあります。バイトコードアセンブラを使用すると、JVMを直接対象とする「マシンコード」を記述できます。また、javacコンパイラが生成できるよりも優れたコードを記述できる場合もあります。とにかく、遊ぶのは楽しいです。

于 2012-07-24T13:42:30.230 に答える
10

Javaコードでアセンブリを直接インライン化することはできません。それにもかかわらず、他のいくつかの回答で主張されていることとは反対に、中間のC(またはC ++)層を経由せずにアセンブリを便利に呼び出すことができます。

クイックウォークスルー

次のJavaクラスについて考えてみます。

public class MyJNIClass {

    public native void printVersion();

}

主なアイデアは、JNI命名規則を使用してシンボルを宣言することです。この場合、アセンブリコードで使用するマングル名はですJava_MyJNIClass_printVersion。このシンボルは、他の変換ユニットから見える必要があります。これは、たとえばpublic、FASMのディレクティブまたはglobalNASMのディレクティブを使用して実現できます。macOSを使用している場合は、名前の前にアンダースコアを追加します。

ターゲットアーキテクチャの呼び出し規約を使用してアセンブリコードを記述します(引数は、レジスタ、スタック、他のメモリ構造などで渡される場合があります)。アセンブリ関数に渡される最初の引数はへのポインタでJNIEnvあり、それ自体がJNI関数テーブルへのポインタです。これを使用して、JNI関数を呼び出します。たとえば、NASMを使用し、x86_64をターゲットにしています。

global Java_MyJNIClass_printVersion

section .text

Java_MyJNIClass_printVersion:
    mov rax, [rdi]
    call [rax + 8*4]  ; pointer size in x86_64 * index of GetVersion
    ...

JNI関数のインデックスは、Javaのドキュメントに記載されています。JNI関数テーブルは基本的にポインターの配列であるため、これらの索引に対象のアーキテクチャーのポインターのサイズを掛けることを忘れないでください。

アセンブリ関数に渡される2番目の引数は、呼び出し元のJavaクラスまたはオブジェクトへの参照です。以降のすべての引数は、ネイティブJavaメソッドのパラメーターです。

最後に、コードをアセンブルしてオブジェクトファイルを生成し、そのオブジェクトファイルから共有ライブラリを作成します。GCCとClangは、。と同様のコマンドを使用してこの最後のステップを実行できますgcc/clang -shared -o ...

追加のリソース

このDZoneの記事では、より包括的なウォークスルーを利用できます。また、GitHubで完全に実行可能な例を作成しました。理解を深めるために、自由に見て、試してみてください。

于 2017-05-11T22:13:10.540 に答える
2

マシンレベルのJavaテクノロジを使用して、Javaからアセンブリを呼び出すことができます。Javaで記述されたアセンブリコードを透過的にパックしますが、最もよく使用されるアセンブリ構文と非常によく似ています。次に、アセンブリが記述されている同じクラスで定義するネイティブメソッドを呼び出す必要があります。したがって、常にJava環境内にとどまり、JavaIDEからいくつかのアセンブリツールに切り替えてからJavaに戻る必要はありません。

于 2014-12-31T00:31:47.260 に答える
1

Javaから直接アセンブリを呼び出すことはできません。ただし、 JNIを介してCコードを呼び出すことができ、そこからアセンブリを呼び出すことができます。

この記事ではその方法を説明します。

于 2012-07-24T13:43:16.310 に答える
1

JNIまたはJNAを使用して、Javaからネイティブ関数を呼び出します。または、別の方法として、InputStreamとしてバイトコードを使用し、それからJavaクラスを作成します。

于 2012-07-24T13:44:04.270 に答える
1

また、Aparapiもご覧になることをお勧めします。

于 2012-07-26T10:51:18.470 に答える