以前HotSpot VMのIntrinsicsを見ました。ビルド時にAD(Architecture Description)ファイルから各CPUアーキテクチャに合わせたC++のソースファイルを生成しています。
しかし、ADファイルからどのようにC++のソースを生成しているのか理解していません。
OpenJDKのビルド後buildディレクトリの中にADファイルから生成されたソースがあります(例: build/macosx-x86_64-normal-server-release/hotspot/variant-server/gensrc/adfiles)。
$ ls build/macosx-x86_64-normal-server-release/hotspot/variant-server/gensrc/adfiles adGlobals_x86.hpp ad_x86.hpp ad_x86_expand.cpp ad_x86_gen.cpp ad_x86_peephole.cpp dfa_x86.cpp ad_x86.cpp ad_x86_clone.cpp ad_x86_format.cpp ad_x86_misc.cpp ad_x86_pipeline.cpp
これらのファイルがどのように生成されるのかを調べました。
ADファイルの内容
ADファイルはsrc/hotspot/cpu
以下の各CPUディレクトリの中にあります。ファイルの内容を抜粋します。
reg_def XMM31p( SOC, SOC, Op_RegF, 31, xmm31->as_VMReg()->next(15)); ... alloc_class chunk1(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0g, XMM0h, XMM0i, XMM0j, XMM0k, XMM0l, XMM0m, XMM0n, XMM0o, XMM0p, ... );
関数呼び出しのようです。実は、ADファイルの中身はArchitecture Description Languageという言語で書かれています。そのシンタックスはsrc/hotspot/share/adlc/Doc/Syntax.doc
に記述されています。
ADファイルのパース
src/hotspot/share/adlc
ディレクトリにAD言語をパースするC++のソースがあります。
$ ls Doc adlc.hpp adlparse.hpp archDesc.hpp arena.hpp dict2.cpp filebuff.cpp forms.cpp formsopt.cpp formssel.cpp main.cpp output_h.cpp Test adlparse.cpp archDesc.cpp arena.cpp dfa.cpp dict2.hpp filebuff.hpp forms.hpp formsopt.hpp formssel.hpp output_c.cpp
adlparse.hpp
を見ます。
// Parse components of the register section void reg_def_parse(void); // Parse register definition void reg_class_parse(void); // Parse register class definition void reg_class_dynamic_parse(void); // Parse dynamic register class definition void alloc_class_parse(void); // Parse allocation class definition
ADファイルにあったreg_def
やalloc_class
をパースする関数が定義されているとわかります。main.cpp
からADLParserが呼び出されています。
ADL_Parse = new ADLParser(ADL_Buf, AD); // Create a parser to parse the buffer ADL_Parse->parse(); // Parse buffer & build description lists
これらの関数は誰が呼び出しているのか?
ここで詰まりました。ビルド時にADファイルから生成している以上、ビルド時に何かがこのadlcのソースを呼び出しているはずです。それがうまく見つかりません。
ビルド時なのでmakeのコードにあるだろうと調べました。するとmake/hotspot/gensrc
ディレクトリというものがありました。
$ ls GenerateSources.gmk GensrcAdlc.gmk GensrcDtrace.gmk GensrcJfr.gmk GensrcJvmti.gmk
GensrcAdlc.gmk
、いかにもですね。このファイルの後ろの方にこうありました。
# Finally copy the generated files from support/adlc into gensrc/adfiles, # and postprocess them by fixing dummy #line directives. ADLC_GENERATED_FILES := $(addprefix $(JVM_VARIANT_OUTPUTDIR)/gensrc/adfiles/, \ ad_$(HOTSPOT_TARGET_CPU_ARCH).cpp \ ad_$(HOTSPOT_TARGET_CPU_ARCH).hpp \ ad_$(HOTSPOT_TARGET_CPU_ARCH)_clone.cpp \ ad_$(HOTSPOT_TARGET_CPU_ARCH)_expand.cpp \ ad_$(HOTSPOT_TARGET_CPU_ARCH)_format.cpp \ ad_$(HOTSPOT_TARGET_CPU_ARCH)_gen.cpp \ ad_$(HOTSPOT_TARGET_CPU_ARCH)_misc.cpp \ ad_$(HOTSPOT_TARGET_CPU_ARCH)_peephole.cpp \ ad_$(HOTSPOT_TARGET_CPU_ARCH)_pipeline.cpp \ adGlobals_$(HOTSPOT_TARGET_CPU_ARCH).hpp \ dfa_$(HOTSPOT_TARGET_CPU_ARCH).cpp \ )
support/adlc
ディレクトリからgensrc/adfiles
ディレクトリにファイルをコピー、そのファイルというのはad_$(HOTSPOT_TARGET_CPU_ARCH).cpp
などです。この投稿の始めに書いた、ad_x86.cpp
といったファイルはぴったりマッチします。ここでADファイルからソースを生成しているので間違いないでしょう。前の方に戻りながら見ます。
############################################################################## # Run the adlc tool on the single concatenated ad source file, and store the # output in support/adlc for further processing. ADLC_RUN_MARKER := $(ADLC_SUPPORT_DIR)/_adlc_run.marker $(ADLC_RUN_MARKER): $(BUILD_ADLC) $(SINGLE_AD_SRCFILE) $(call LogInfo, Generating adlc files) $(call MakeDir, $(@D)) $(call ExecuteWithLog, $(ADLC_SUPPORT_DIR)/adlc_run, \ $(FIXPATH) $(ADLC_TOOL) $(ADLCFLAGS) $(SINGLE_AD_SRCFILE) \ -c$(ADLC_SUPPORT_DIR)/ad_$(HOTSPOT_TARGET_CPU_ARCH).cpp \ -h$(ADLC_SUPPORT_DIR)/ad_$(HOTSPOT_TARGET_CPU_ARCH).hpp \ -a$(ADLC_SUPPORT_DIR)/dfa_$(HOTSPOT_TARGET_CPU_ARCH).cpp \ -v$(ADLC_SUPPORT_DIR)/adGlobals_$(HOTSPOT_TARGET_CPU_ARCH).hpp) $(TOUCH) $@
$(ADLC_SUPPORT_DIR)/adlc_run
を実行しています。これは実際にはbuild/macosx-x86_64-normal-server-release/hotspot/variant-server/support/adlc
ディレクトリです。adlc_run.cmdline
というファイルがあります。
/Users/koichi.sakata/code/loom/build/macosx-x86_64-normal-server-release/hotspot/variant-server/tools/adlc/adlc -q -T -D_ALLBSD_SOURCE=1 -D_GNU_SOURCE=1 -g -DAMD64=1 -D_LP64=1 /Users/koichi.sakata/code/loom/build/macosx-x86_64-normal-server-release/hotspot/variant-server/support/adlc/all-ad-src.ad -c/Users/koichi.sakata/code/loom/build/macosx-x86_64-normal-server-release/hotspot/variant-server/support/adlc/ad_x86.cpp -h/Users/koichi.sakata/code/loom/build/macosx-x86_64-normal-server-release/hotspot/variant-server/support/adlc/ad_x86.hpp -a/Users/koichi.sakata/code/loom/build/macosx-x86_64-normal-server-release/hotspot/variant-server/support/adlc/dfa_x86.cpp -v/Users/koichi.sakata/code/loom/build/macosx-x86_64-normal-server-release/hotspot/variant-server/support/adlc/adGlobals_x86.hpp
hotspot/variant-server/tools/adlc/adlc
にオプションでad_x86.cppを渡しています。ここで生成しているのでしょう。
hotspot/variant-server/tools/adlc/adlc
はバイナリでした。さらに前に戻ります。
$(eval $(call SetupNativeCompilation, BUILD_ADLC, \ NAME := adlc, \ TYPE := EXECUTABLE, \ TOOLCHAIN := TOOLCHAIN_BUILD_LINK_CXX, \ SRC := $(TOPDIR)/src/hotspot/share/adlc, \ EXTRA_FILES := $(TOPDIR)/src/hotspot/share/opto/opcodes.cpp, \ CFLAGS := $(ADLC_CFLAGS) $(ADLC_CFLAGS_WARNINGS), \ LDFLAGS := $(ADLC_LDFLAGS), \ LIBS := $(ADLC_LIBS), \ OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/adlc/objs, \ OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/adlc, \ DEBUG_SYMBOLS := false, \ DISABLED_WARNINGS_clang := tautological-compare, \ DISABLED_WARNINGS_solstudio := notemsource, \ ))
SetupNativeCompilation
を呼んで、EXECUTABLEなhotspot/variant-server/tools/adlc/adlc
を生成していると読めます。SetupNativeCompilation
を検索すると、make/common/NativeCompilation.gmk
に定義されていました。
################################################################################ # Create the recipe needed to compile a single native source file. # # Parameter 1 is the name of the rule, based on the name of the library/ # program being build and the name of the source code file, e.g. # BUILD_LIBFOO_fooMain.cpp. # # Remaining parameters are named arguments: # FILE - The full path of the source file to compiler # BASE - The name of the rule for the entire binary to build ($1) # DISABLE_THIS_FILE_DEFINE - Set to true to disable the THIS_FILE define. # SetupCompileNativeFile = $(NamedParamsMacroTemplate) define SetupCompileNativeFileBody
まとめ
HotSpot VMではビルド時に使用しているCPUのADファイルをパースして、そのCPUに合わせたC++のソースファイルを生成していることがわかりました。これはmakeのコードから呼び出されています。またADファイルはいわばDSLで書かれたものと捉えることができます。
また少し、HotSpot VMの理解が深まりました。