1. 程式人生 > 其它 >JVM詳解之:HotSpot VM中的Intrinsic methods

JVM詳解之:HotSpot VM中的Intrinsic methods

簡介

內建方法是什麼呢?它和inline method有什麼關係呢?內建方法是怎麼實現的呢?所有的問題都可以在本文找到答案。

什麼是Intrinsic Methods

什麼是內建方法呢?

維基百科給出的定義是這樣的:

在計算機軟體中,按照編譯器理論,固有方法(或內建方法)是可在給定程式語言中使用的方法,該程式語言的實現由編譯器專門處理。通常,它可以將自動生成的指令序列替換為原始方法呼叫,類似於內聯方法。與內聯方法不同,編譯器對內建方法有深入的瞭解,因此可以針對給定情況更好地整合和優化它。

實現內建方法的編譯器通常僅在程式請求優化時才啟用它們,否則會退回到語言執行時環境提供的預設實現。

所以總結一下,內建方法就是編譯器內建的方法實現。

內建方法的特點

內建方法有什麼特點呢?我們在這裡總結一下。

01

多樣性

因為內建方法是在編譯器內部實現的,所以不同的虛擬機器,其內建方法是不一樣的。

我們不能直接說哪個方法是內建方法,因為不同的JVM是不同的。

02

相容性

內建方法是在需要的時候才會使用的,如果在不需要的時候則會回退到普通的方法實現,也就是java程式碼的實現。

所以在java原始碼級別來看,內建方法和非內建方法是一樣的。他們的區別在於JVM的實現。

03

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):

https://gist.github.com/rednaxelafx/2830194

C2級別修改(Example (XS) of adding an intrinsic method to HotSpot C2. Patch against HS20-b12):

https://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方法是一個非常有用的特性,希望大家能夠喜歡。