Dalvik VM compilation script and source code tree
This article briefly analyzes the structure of Dalvik Virtual Machine source code (Dalvik/Vm) and the compilation script (*. mk)
Compile scripts
The directory structure of Dalvik source code is not complex. The compilation script is also very simple. It consists of the following files:
Dalvik/Vm/Android. mk
Dalvik/Vm/reconfiguredvm. mk
Dalvik/Vm/DVM. mk
Similar to other modules in the Android system, Dalvik uses Android. mk as the top-level compilation configuration file or entry. Its content is as follows:
Https://github.com/android/platform_dalvik/blob/master/vm/Android.mk
Let's analyze it from scratch. Note the following for the first time:
## Android.mk for Dalvik VM.## This makefile builds both for host and target, and so the very large# swath of common definitions are factored out into a separate file to# minimize duplication.## If you enable or disable optional features here (or in Dvm.mk),# rebuild the VM with:## make clean-libdvm clean-libdvm_assert clean-libdvm_sv clean-libdvm_interp# make -j4 libdvm#
He told us that the compilation file programmed Dalvik into two parts: Host Machine and target machine. In most typical configurations, the host machine is our Linux compilation server. The target machine is our mobile device. To reduce duplication, the compilation configurations required by both the host machine and the target machine are put in a separate file. A separate file is followed by ethics (reconfiguredvm. mk and DVM. mk ).
At the same time, it should also come out after we modified the Dalvik source code, how to compile a clean implementation from the beginning. We will practice it later.
LOCAL_PATH:= $(call my-dir)
Like most modules, assign the Dalvik source code path to the local_path variable. To facilitate later use. Here local_path should be Dalvik/VM.
## Build for the target (device).#ifeq ($(TARGET_CPU_SMP),true) target_smp_flag := -DANDROID_SMP=1else target_smp_flag := -DANDROID_SMP=0endifhost_smp_flag := -DANDROID_SMP=1# Build the installed version (libdvm.so) firstinclude $(LOCAL_PATH)/ReconfigureDvm.mk# Overwrite default settingsLOCAL_MODULE_TAGS := optionalLOCAL_MODULE := libdvmLOCAL_CFLAGS += $(target_smp_flag)include $(BUILD_SHARED_LIBRARY)
Compile for the target machine first. First, set the variable target_smp_flag based on whether the target machine supports SMP. Later we will see that this variable is used to pass to the compiler options. Most hosts currently support SMP, so direct replication is supported.
Then we call the script reconfiguredvm. mk. From the name, we can easily guess that the script is used to initialize the compiling environment for DVM compilation. We will see its main content later.
The following is the final compilation target of the actual DVM on the host machine. This is a shared library. The name is libdvm. We can find it on the compiled machine.
Out/target/XXX/libs/libdvm. So
# If WITH_JIT is configured, build multiple versions of libdvm.so to facilitate# correctness/performance bugs triageifeq ($(WITH_JIT),true) # Derivation #1 # Enable assert and JIT tuning include $(LOCAL_PATH)/ReconfigureDvm.mk # Enable assertions and JIT-tuning LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT \ -DWITH_JIT_TUNING $(target_smp_flag) LOCAL_MODULE := libdvm_assert include $(BUILD_SHARED_LIBRARY) # Derivation #2 # Enable assert and self-verification include $(LOCAL_PATH)/ReconfigureDvm.mk # Enable assertions and JIT self-verification LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT \ -DWITH_SELF_VERIFICATION $(target_smp_flag) LOCAL_MODULE := libdvm_sv include $(BUILD_SHARED_LIBRARY) # Derivation #3 # Compile out the JIT WITH_JIT := false include $(LOCAL_PATH)/ReconfigureDvm.mk LOCAL_CFLAGS += $(target_smp_flag) LOCAL_MODULE := libdvm_interp include $(BUILD_SHARED_LIBRARY)endif
This part is special to JIT. When the system supports the JIT compiler, DVM compiles three additional target shared libraries to Support the Development Features of DVM. They are
Libdvm_assert is used to open assert in the DVM source code ). We will see in subsequent analysis articles that a large number of assertions are used in DVM implementation to increase runtime checks. When you enable these assertions, any failure in the assertion check will directly cause the DVM to exit unexpectedly. We can find the asserted failure from the trace file to check for possible bugs. In the final release version, assertions will be closed, and which assertions are equivalent to null statements. Therefore, the client will not exit unexpectedly when the final version is DVM.
In addition to assertion, libdvm_sv also provides the self-check capability to check whether the current DVM status is abnormal at some important moments. In the subsequent articles, we will analyze in detail what self-Checks DVM has done.
In the last version, libdvm_interp is used to turn off JIT and compile a DVM instance implemented by the pure interpreter. In this way, we can check whether the behavior after JIT is enabled is different from the DVM implemented by the interpreter.
We can find the three DVM shared libraries generated for debugging in the following directory:
Out/target/XXX/symbol/libs/
The final content is used for compiling the host. All content is wrapped in the following code:
## Build for the host.#ifeq ($(WITH_HOST_DALVIK),true)
...
endif
First, clear the local variable content:
include $(CLEAR_VARS)
Then, set three compilation variables based on the compiling environment:
# Variables used in the included Dvm.mk. dvm_os := $(HOST_OS) dvm_arch := $(HOST_ARCH) # Note: HOST_ARCH_VARIANT isn't defined. dvm_arch_variant := $(HOST_ARCH)
These three variables will eventually be passed to the compiler. They introduce platform-specific behaviors. Because the host does not need to support JIT, set it to false.
WITH_JIT := false
include $(LOCAL_PATH)/Dvm.mk
DVM. mk will be analyzed later.
Next, we will introduce the required libraries for compilation based on the Target Platform:
LOCAL_SHARED_LIBRARIES += libcrypto libssl libicuuc libicui18n LOCAL_LDLIBS := -lpthread -ldl ifeq ($(HOST_OS),linux) # need this for clock_gettime() in profiling LOCAL_LDLIBS += -lrt endif # Build as a WHOLE static library so dependencies are available at link # time. When building this target as a regular static library, certain # dependencies like expat are not found by the linker. LOCAL_WHOLE_STATIC_LIBRARIES += libexpat libcutils libdex liblog libnativehelper libz # The libffi from the source tree should never be used by host builds. # The recommendation is that host builds should always either # have sufficient custom code so that libffi isn't needed at all, # or they should use the platform's provided libffi. So, if the common # build rules decided to include it, axe it back out here. ifneq (,$(findstring libffi,$(LOCAL_SHARED_LIBRARIES))) LOCAL_SHARED_LIBRARIES := \ $(patsubst libffi, ,$(LOCAL_SHARED_LIBRARIES)) endif
Finally, the compilation system is told that DVM has two compilation results on the host:
LOCAL_CFLAGS += $(host_smp_flag) LOCAL_MODULE_TAGS := optional LOCAL_MODULE := libdvm include $(BUILD_HOST_SHARED_LIBRARY) # Copy the dalvik shell script to the host's bin directory include $(CLEAR_VARS) LOCAL_IS_HOST_MODULE := true LOCAL_MODULE_TAGS := optional LOCAL_MODULE_CLASS := EXECUTABLES LOCAL_MODULE := dalvik include $(BUILD_SYSTEM)/base_rules.mk$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/dalvik | $(ACP)@echo "Copy: $(PRIVATE_MODULE) ($@)"$(copy-file-to-new-target)$(hide) chmod 755 $@
They are the DVM shared library libdvm. So and the executable file dalvikvm. We can find them in the compiled directory:
Out/host/XXX/libs/libdvm. So
Out/host/XXX/bin/dalvikvm
As we can see above, DVM may have several compilation results on the target machine, the ultimate shared library libdvm. So, and several shared libraries libsdvm_xx.so used by developers. To compile these goals, we need to first clean up the current compilation environment to eliminate the side effects of the previous goal. This work is put separately in the compilation script reconfiguredvm. mk to reduce duplication. The reconfiguredvm. mk content is as follows:
include $(CLEAR_VARS)# Variables used in the included Dvm.mk.dvm_os := $(TARGET_OS)dvm_arch := $(TARGET_ARCH)dvm_arch_variant := $(TARGET_ARCH_VARIANT)# for now, disable x86-atom variantifeq ($(dvm_arch_variant),x86-atom)dvm_arch_variant := x86endifinclude $(LOCAL_PATH)/Dvm.mkLOCAL_SHARED_LIBRARIES += liblog libcutils libnativehelper libz libdlLOCAL_STATIC_LIBRARIES += libdexLOCAL_C_INCLUDES += external/stlport/stlport bionic/ bionic/libstdc++/includeLOCAL_SHARED_LIBRARIES += libstlport# Don't install on any build by defaultLOCAL_MODULE_TAGS := optional
Its content is not surprising. Clear local variables, set DVM variables, and introduce the library required by DVM. Finally, set local_module_tags to optional to tell the compiling system that DVM will not be compiled unless explicitly specified (include Dalvik/Vm/Android. mk.
The last file DVM. mk sets the definitions required for both the host machine and the target machine. Its content is also intuitive. The complete content is as follows:
Https://github.com/android/platform_dalvik/blob/master/vm/Dvm.mk
First, set the compiler options:
## Compiler defines.#LOCAL_CFLAGS += -fstrict-aliasing -Wstrict-aliasing=2 -fno-align-jumpsLOCAL_CFLAGS += -Wall -Wextra -Wno-unused-parameterLOCAL_CFLAGS += -DARCH_VARIANT=\"$(dvm_arch_variant)\"
Then, determine whether debug_dalvik_vm is specified during compilation:
## Optional features. These may impact the size or performance of the VM.## Make a debugging version when building the simulator (if not told# otherwise) and when explicitly asked.dvm_make_debug_vm := falseifneq ($(strip $(DEBUG_DALVIK_VM)),) dvm_make_debug_vm := $(DEBUG_DALVIK_VM)endif
If this option is specified, additional compilation options are enabled. Otherwise, nothing is done:
ifeq ($(dvm_make_debug_vm),true) # # "Debug" profile: # - debugger enabled # - profiling enabled # - tracked-reference verification enabled # - allocation limits enabled # - GDB helpers enabled # - LOGV # - assert() # LOCAL_CFLAGS += -DWITH_INSTR_CHECKS LOCAL_CFLAGS += -DWITH_EXTRA_OBJECT_VALIDATION LOCAL_CFLAGS += -DWITH_TRACKREF_CHECKS LOCAL_CFLAGS += -DWITH_EXTRA_GC_CHECKS=1 #LOCAL_CFLAGS += -DCHECK_MUTEX LOCAL_CFLAGS += -DDVM_SHOW_EXCEPTION=3 # add some extra stuff to make it easier to examine with GDB LOCAL_CFLAGS += -DEASY_GDB # overall config may be for a "release" build, so reconfigure these LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERTelse # !dvm_make_debug_vm # # "Performance" profile: # - all development features disabled # - compiler optimizations enabled (redundant for "release" builds) # - (debugging and profiling still enabled) # #LOCAL_CFLAGS += -DNDEBUG -DLOG_NDEBUG=1 # "-O2" is redundant for device (release) but useful for sim (debug) #LOCAL_CFLAGS += -O2 -Winline #LOCAL_CFLAGS += -DWITH_EXTRA_OBJECT_VALIDATION LOCAL_CFLAGS += -DDVM_SHOW_EXCEPTION=1 # if you want to try with assertions on the device, add: #LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERTendif # !dvm_make_debug_vm
Next is the big head of the file, introduce the source file for compilation. These include the source files used by all platforms, such as alloctracker. cpp. To support jit-specific files, such as Compiler/compiler. cpp. The following sections require special attention:
ifeq ($(WITH_COPYING_GC),true) LOCAL_CFLAGS += -DWITH_COPYING_GC LOCAL_SRC_FILES += \alloc/Copying.cpp.armelse LOCAL_SRC_FILES += \alloc/HeapSource.cpp \alloc/MarkSweep.cpp.armendif
This is the type of the specified garbage collector. When with_copying_gc is specified in the compilation option, the copy garbage collector is used; otherwise, the garbage collector is marked with-cleared. We will introduce DVM garbage collection in separate chapters later.
At this point, the parsing of the compiled script is complete. The source code structure of DVM is simple and Its compiling script is clear.
Source code directory tree
Below is the DVM source code directory tree. The following sections describe the most important parts:
Https://github.com/android/platform_dalvik/tree/master/vm