如何編譯"零彙編(Zero-Assembler)"的OpenJDK

在使用JetBrains CLion調試OpenJDK的過程當中,有時候會發現Call Stack中有一部分是彙編代碼,致使沒法徹底探究其內部實現。本文主要針對此問題給出瞭如何在不引入彙編代碼(零彙編,Zero-Assembler)的狀況下完成OpenJDK項目的編譯和調試。html

OpenJDK 編譯調試指南一文中,已經詳細介紹了編譯調試OpenJDK的步驟,這裏再也不詳述具體過程。java

爲何存在部分彙編代碼?

首先咱們來看下爲何會存在部分彙編代碼,以及這部分彙編代碼是什麼? 從 HotSpot Runtime Overview - Interpreter 瞭解到,HotSpot爲了提升性能,使用了基於模板的解釋器(template based interpreter)來解釋執行JAVA虛擬機指令JVM在啓動時會根據TemplateTable(與每一個字節碼對應的彙編代碼)來生成解釋器,因此說這個解釋器實際上是部分基於彙編代碼實現的。除了解釋器以外,在OpenJDK項目中還有一些部分也是基於彙編代碼的,例如即時編譯器JITC1編譯器,C2編譯器)等,但彙編代碼是依賴於硬件架構的,這種作法在提高了性能的同時卻下降了可移植性。macos

OpenJDK社區的IcedTea項目提供了一種比較通用的移植方法,使得OpenJDK能夠在全部的Linux系統上構建, 而無需進一步進行移植工做。bash

IcedTea項目

IcedTea項目最初的出現是由於Sun公司在發佈JDK時,類庫的一些部分因爲產權緣由沒有發佈其源代碼,而是僅以二進制插件的形式提供, 由於這部分源代碼屬於受版權保護的第三方。IcedTea的主要目標就是提供這些二進制插件的免費等效替代品,使得徹底使用免費開源軟件構建JDK成爲可能。markdown

此外,IdeaTea還作了不少工做以促進用戶更容易地構建和部署JDK,其中包括將OpenJDK移植到更多的平臺。架構

由於OpenJDK的代碼中除了 C++ 代碼以外還包含許多彙編代碼,而OpenJDK支持的硬件平臺架構有限,遠遠少於Linux系統所支持的。因而IcedTea的子項目Zero出現了,Zero項目旨在經過移除OpenJDK項目代碼中的與平臺相關的彙編代碼,使用純C++來替代,從而能夠在任何 Linux 系統上構建,而無需進一步進行移植工做。jvm

這也正是標題中"零彙編"的含義所在,就是指不使用匯編代碼來構建OpenJDKide

OpenJDK 的虛擬機在很大程度上依賴 JIT(即時編譯器) 編譯來提升性能。而Zero中只包含一個純C++解釋器,Zero 在相同的硬件上要比原始(vanilla)的 OpenJDK 慢得多。因而又一個子項目Shark出現了, Shark使用 LLVM 來即時編譯 Java 代碼,從而在不引入系統特定的代碼的狀況下提升性能。oop

如何實現"零彙編(Zero-Assembler)"

到這裏咱們已經明白了,使用zero來構建OpenJDK就能夠實現"零彙編(Zero-Assembler)",那麼如何使用呢?目前ZeroShark已經集成到了OpenJDK的主分支中,只要在配置OpenJDK的時候指定參數--with-jvm-variants=zero從新編譯便可。post

雖然在OpenJDK 8中提供了--with-jvm-variants=zeroshark的配置項,但通過幾番嘗試發現並不能真正構建成功。根據OpenJDK社區的一些資料([JDK-8171853] Remove Shark compiler - Java Bug Systemjdk-updates/jdk10u: fb290fd1f9d4), Shark因爲長期缺少維護已經在JDK 10版本中被移除了,也再也不支持配置--with-jvm-variants=zeroshark參數了。因此下文咱們只考慮Zero而不設計Shark相關內容。

這篇文章Sustaining the zero assembler port in OpenJDK: An inside perspective of CPU specific issues比較形象地描述了模板解釋器C++解釋器的區別,以及如何構建zero版的OpenJDK,推薦閱讀。

下面主要記錄一下在MacOSUbuntu平臺下編譯ZeroOpenJDK所遇到的問題。

Ubuntu 16.04

Ubuntu 16.04平臺上編譯OpenJDK 8時遇到的一個問題是缺乏 libffi 依賴。運行configure時出現下面的錯誤信息:

checking for LIBFFI... configure: error: Package requirements (libffi) were not met:
No package 'libffi' found
複製代碼

使用以下命令安裝以後從新配置編譯便可:

sudo apt-get install libffi-dev
複製代碼

Ubuntu 16.04平臺上編譯OpenJDK 11時沒有問題,很順利就編譯完成了。

MacOS 10.15

MacOS 10.15平臺上編譯時遇到較多問題,主要緣由是OpenJDK項目對MacOS平臺編譯zero版本 支持不夠完善,致使有一些代碼編譯不經過。

OpenJDK 8

  1. 運行configure出現下面的錯誤信息:
checking for LIBFFI... configure: error: in `/Users/jiajiawang/Workspace/openjdk-jdk8u':
configure: error: The pkg-config script could not be found or is too old.  Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
複製代碼

一樣是由於缺乏了libffi庫,除了libffi以外還缺乏pkg-config,使用HomeBrew安裝這兩個依賴便可:

brew install libffi pkg-config
複製代碼
  1. configure完成,運行make時出現下面的錯誤信息:
/usr/bin/clang++  ...  ... ... openjdk-jdk8u/hotspot/src/share/vm/precompiled/precompiled.hpp -o precompiled.hpp.pch 
clang: error: unsupported option '-gstabs'
複製代碼

這是由於clang不支持gcc-gstabs選項,須要對hotspot/make/bsd/makefiles/gcc.make文件進行修改,修改內容以下:

DEBUG_CFLAGS/ppc   = -g
   DEBUG_CFLAGS += $(DEBUG_CFLAGS/$(BUILDARCH))
   ifeq ($(DEBUG_CFLAGS/$(BUILDARCH)),)
- DEBUG_CFLAGS += -gstabs
+ ifeq ($(USE_CLANG), true)
+ # Clang doesn't understand -gstabs
+ DEBUG_CFLAGS += -g
+ else
+ DEBUG_CFLAGS += -gstabs
+ endif
   endif
複製代碼
  1. 繼續運行make時出現下面的錯誤信息:
... ... ... /src/os/bsd/vm/os_perf_bsd.cpp:29:10: fatal error: 'vm_version_ext_x86.hpp' file not found
#include "vm_version_ext_x86.hpp"
         ^~~~~~~~~~~~~~~~~~~~~~~~
複製代碼

這裏引入了錯誤的文件,須要對hotspot/src/os/bsd/vm/os_perf_bsd.cpp作以下修改,使其引入正確的vm_version_ext_zero.hpp文件:

#include "memory/resourceArea.hpp"
 #include "runtime/os.hpp"
 #include "runtime/os_perf.hpp"
-#include "vm_version_ext_x86.hpp"
+
+#ifdef TARGET_ARCH_aarch32
+# include "vm_version_ext_aarch32.hpp"
+#endif
+#ifdef TARGET_ARCH_x86
+# include "vm_version_ext_x86.hpp"
+#endif
+#ifdef TARGET_ARCH_sparc
+# include "vm_version_ext_sparc.hpp"
+#endif
+#ifdef TARGET_ARCH_zero
+# include "vm_version_ext_zero.hpp"
+#endif
+#ifdef TARGET_ARCH_arm
+# include "vm_version_ext_arm.hpp"
+#endif
+#ifdef TARGET_ARCH_ppc
+# include "vm_version_ext_ppc.hpp"
+#endif
複製代碼
  1. 繼續運行make時出現下面的錯誤信息:
make[2]: *** No rule to make target ` ... ... openjdk-jdk8u/jdk/src/macosx/bin/zero/jvm.cfg', needed by ` ... ... openjdk-jdk8u/build/macosx-x86_64-normal-zero-slowdebug/jdk/lib/jvm.cfg'.  Stop.
複製代碼

缺乏jdk/src/macosx/bin/zero/jvm.cfg文件,咱們從其餘目錄拷貝一份過來:

mkdir -p jdk/src/macosx/bin/zero/
cp jdk/src/macosx/bin/x86_64/jvm.cfg jdk/src/macosx/bin/zero
複製代碼

OpenJDK 11

  1. 運行configure出現下面的錯誤信息:
checking for ffi.h... no
configure: error: Could not find libffi! 
複製代碼

一樣是由於缺乏ligffi依賴,與OpenJDK 8不一樣的是在OpenJDK 11中,安裝 libffi以後須要經過--with-libffi=<path>來指定libffi的地址:

# 安裝libffi
brew install libffi
# 配置
sh ./configure ...省略其餘參數... --with-jvm-variants=zero --with-libffi=/usr/local/Cellar/libffi/3.3/
複製代碼
  1. configure完成,執行make出現下面的錯誤信息:
... ... ... /openjdk-jdk11u/src/hotspot/share/interpreter/bytecodeInterpreter.cpp:2926:13: error: 7 enumeration values not handled in switch: 'T_VOID', 'T_ADDRESS', 'T_NARROWOOP'... [-Werror,-Wswitch]
    switch (istate->method()->result_type()) {
            ^
... ... ... /openjdk-jdk11u/src/hotspot/share/interpreter/bytecodeInterpreter.cpp:2926:13: note: add missing switch cases
    switch (istate->method()->result_type()) {
            ^
複製代碼

這是由於源代碼中的switch語句沒有處理全部的分支狀況,全部clang給出了警告(Diagnostic),致使編譯不經過,咱們能夠經過clang-w參數來取消全部的警告(Diagnostic),須要在配置時添加以下兩個參數,從新編譯便可:

sh ./configure  ...省略其餘參數... --with-extra-cflags=-w --with-extra-cxxflags=-w
複製代碼
  1. 繼續運行make時出現下面的錯誤信息:
... ... ... /src/os/bsd/vm/os_perf_bsd.cpp:29:10: fatal error: 'vm_version_ext_x86.hpp' file not found
#include "vm_version_ext_x86.hpp"
         ^~~~~~~~~~~~~~~~~~~~~~~~
複製代碼

這裏引入了錯誤的文件,須要對src/hotspot/os/bsd/os_perf_bsd.cpp作以下修改,使其引入正確的vm_version_ext_zero.hpp文件(與OpenJDK 8中稍有不一樣):

#include "runtime/os.hpp"
 #include "runtime/os_perf.hpp"
 #include "utilities/globalDefinitions.hpp"
-#include "vm_version_ext_x86.hpp"
+
+#include CPU_HEADER(vm_version_ext)
複製代碼

參考資料

  1. HotSpot Runtime Overview - Interpreter
  2. Sustaining the zero assembler port in OpenJDK: An inside perspective of CPU specific issues
  3. Demystifying the JVM: JVM Variants, Cppinterpreter and TemplateInterpreter
  4. OpenJDK: IcedTea Project
  5. IcedTea - Wikipedia
  6. Main Page - IcedTea
  7. Zero-Assembler Project
  8. ZeroSharkFaq - IcedTea
  9. The New Hotspot Build System
相關文章
相關標籤/搜索