JVM詳解之:HotSpot VM中的Intrinsic methods
簡介
內置方法是什麼呢?它和inline method有什麼關係呢?內置方法是怎麼實現的呢?所有的問題都可以在本文找到答案。
什麼是Intrinsic Methods
什麼是內置方法呢?
維基百科給出的定義是這樣的:
在計算機軟件中,按照編譯器理論,固有方法(或內置方法)是可在給定編程語言中使用的方法,該編程語言的實現由編譯器專門處理。通常,它可以將自動生成的指令序列替換為原始方法調用,類似於內聯方法。與內聯方法不同,編譯器對內置方法有深入的了解,因此可以針對給定情況更好地集成和優化它。
實現內置方法的編譯器通常僅在程序請求優化時才啟用它們,否則會退回到語言運行時環境提供的默認實現。
所以總結一下,內置方法就是編譯器內置的方法實現。
內置方法的特點
內置方法有什麼特點呢?我們在這裡總結一下。
多樣性
因為內置方法是在編譯器內部實現的,所以不同的虛擬機,其內置方法是不一樣的。
我們不能直接說哪個方法是內置方法,因為不同的JVM是不同的。
兼容性
內置方法是在需要的時候才會使用的,如果在不需要的時候則會回退到普通的方法實現,也就是java代碼的實現。
所以在java源代碼級別來看,內置方法和非內置方法是一樣的。他們的區別在於JVM的實現。
java語義的擴展
有些方法用普通的java代碼是無法實現的。比如sun.misc.Unsafe.compareAndSwapInt()。
我們只能使用JNI或者內置方法來對其實現。所以內置方法可以實現對java語義的擴展。
一般來說,JDK和核心庫中,能使用內置方法優化都已經優化了。所以我們在平時的代碼調用中,一定要儘可能的使用JDK的公共API和核心庫,這樣才能充分利用內置方法的特性,從而提升程序效率。
Hotspot VM中的內置方法
那麼對於Hotspot VM來說,內置的方法有哪些呢?
Hotspot VM中所有的內置方法都在src/share/vm/classfile/vmSymbols.hpp類中:
上圖我只截取了部分標記為intrinsic方法的類的說明。
可以看到java.lang.Math中大部分的方法都是intrinsic的方法。
怎麼查看我們代碼中調用的方法是不是intrinsic方法呢?
很簡單,在java命令之前加上這些參數即可:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining
舉個最常用的查看java版本的例子:
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining version
看下輸出結果:
從結果可以很清楚的看到,java.lang.System.arraycopy方法是內置方法。
另外我們可以通過更加底層的彙編語言來查看,再添加
-XX:+PrintAssembly
我們看下輸出結果:
invokestatic意味着該方法就是intrinsified方法。
intrinsic方法和內聯方法
內聯方法就是把調用方函數代碼”複製”到調用方函數中,減少因函數調用開銷的技術。
intrinsic方法大部分都是內聯方法。
intrinsic方法的實現
前面我們提到了內置方法是在編譯器實現的。
在Hotspot VM中其實有3中編譯器。
第一種就是javac將java源代碼編譯成為位元組碼。
在這一層,只有一些math方法和bootstrapping的MethodHandle是在這一層實現的。
第二種就是在JIT的Client Compiler (C1)。
第三種就是在JIT的Server Compiler (C2)。
舉一個例子,我們看一下java.lang.System.currentTimeMillis()方法:
@HotSpotIntrinsicCandidate
public static native long currentTimeMillis();
JDK源碼使用了HotSpotIntrinsicCandidate註解。這個註解只是表示該方法可能會被用於Intrinsic,而並不意味着一定使用Intrinsic。
這個方法在Interpreter級別是沒有intrinsified。因為這是一個native方法,所以會通過JNI調用底層的C++實現。
而在C1和C2級別,會使用intrinsified, 直接調用os::javaTimeMillis()。
好處就是減少了JNI的使用,提升效率。
好了問題來了,我們可以自己實現intrinsified方法嗎?
答案是可以,不過需要修改底層的JVM實現。
這裡有兩個具體的例子,感興趣的大家可以自行研究。
C1級別修改(First cut: C1 Class.isInstance intrinsic):
//gist.github.com/rednaxelafx/2830194
C2級別修改(Example (XS) of adding an intrinsic method to HotSpot C2. Patch against HS20-b12):
//gist.github.com/rednaxelafx/1986224
Graal
因為Hotspot VM是用C++編寫的,如果要添加Intrinsic方法,對於那些不熟悉C++的朋友來說就太難了。
沒關係,Oracle開發了一個項目叫做Graal。 Graal是一個用java編寫的新款JIT編譯器。
Graal是基於Java的JIT編譯器,是JDK 9中引入的實驗性Ahead-of-Time(AOT)編譯器的基礎。
開啟Graal的參數:
-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler
通過Graal,我們可以用java來實現Intrinsic方法,想想就讓人興奮。
總結
Intrinsic方法是一個非常有用的特性,希望大家能夠喜歡。
本文作者:flydean程序那些事
本文鏈接://www.flydean.com/jvm-intrinsic-method/
本文來源:flydean的博客
歡迎關注我的公眾號:程序那些事,更多精彩等着您!