Java中的代码注入/汇编内联?

我知道Java是一种安全的语言,但是当需要进行矩阵计算时,我可以更快地尝试一下吗?

我正在学习C ++,Digital-Mars编译器和FASM中的__asm {}。 我想在Java中做同样的事情。 如何在函数中内联汇编代码? 这有可能吗?

像这样的东西(使用AVX支持CPU将数组的所有元素钳制到没有分支的值的矢量化循环):

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]); 

我不想使用代码注入器。 我想看看英特尔或AT&T风格的x86指令。

您的Java代码和底层硬件之间存在一层抽象,原则上使这种事情变得不可能; 从技术上讲,您无法知道代码在底层机器上的表示方式,因为相同的字节码可以在不同的处理器和不同的体系结构上运行。

你正式可以做的是使用Java Native Interface (JNI)从你的Java代码中调用本机代码。 调用开销很大,并且与Java共享数据相当昂贵,因此这应仅用于体面大小的本机代码块。

理论上,这种扩展应该是可能的。 可以想象一个针对特定平台并允许程序集转义的Java编译器。 编译器必须发布其ABI,因此您将了解调用约定。 但是,我不知道有什么用。 但是有几个 编译器 可以将Java直接编译为本机代码; 有可能其中一个人在我不知情的情况下支持这样的事情,或者可以扩展到这样做。

最后,在一个不同的层面上,JVM有字节码汇编程序,如Jasmin。 字节码汇编程序允许您编写直接面向JVM的“机器代码”,有时您可以编写比javac编译器生成的代码更好的代码。 无论如何,玩它很有趣。

您不能直接在Java代码中内联汇编。 然而,与其他一些答案所声称的相反,方便地调用汇编而不经过任何中间C(或C ++)层是可能的。

快速演练

考虑以下Java类:

 public class MyJNIClass { public native void printVersion(); } 

主要思想是使用JNI命名约定声明符号。 在这种情况下,要在汇编代码中使用的Java_MyJNIClass_printVersion名称是Java_MyJNIClass_printVersion 。 此符号必须在其他翻译单元中可见,例如可以使用FASM中的public指令或NASM中的global指令实现。 如果您使用的是macOS,请在名称前加一个下划线。

使用目标体系结构的调用约定编写汇编代码(参数可以在寄存器,堆栈,其他内存结构等中传递)。 传递给汇编函数的第一个参数是指向JNIEnv的指针, 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 ... 

可以在Java文档中找到JNI函数的索引。 由于JNI函数表基本上是一个指针数组,因此不要忘记将这些索引乘以目标体系结构中指针的大小。

传递给汇编函数的第二个参数是对调用Java类或对象的引用。 所有后续参数都是本机Java方法的参数。

最后,汇编代码以生成目标文件,然后从该目标文件创建共享库。 GCC和Clang可以使用类似于gcc/clang -shared -o ...的命令执行最后一步。

其他资源

这篇DZone文章提供了更全面的演练。 我还在GitHub上创建了一个完全可运行的示例 ,随意查看并使用它来获得更好的理解。

可以使用Machine Level Java技术从Java调用程序集。 它透明地将用Java编写的汇编代码打包到本机库中,但与最常用的汇编语法非常相似。 接下来,您只需要调用一个本机方法,您可以在同一个类中定义程序集的编写位置。 因此,您始终保持在Java环境中,无需从Java IDE切换到某些组装工具,然后再切换回Java。

您无法直接从Java调用程序集。 但是你可以通过JNI调用C代码,然后从那里调用程序集。

这篇文章说明了如何。

您使用JNI或JNA并从Java调用本机函数。 或者作为替代方案,您将字节码作为InputStream并从中创建Java类。

您可能还想看看Aparapi 。