mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-01 19:50:05 +00:00
Merge
This commit is contained in:
commit
157bfcd7da
@ -3,8 +3,7 @@
|
||||
^.idea/
|
||||
nbproject/private/
|
||||
^webrev
|
||||
^.hgtip
|
||||
^.bridge2
|
||||
^.src-rev$
|
||||
^.jib/
|
||||
.DS_Store
|
||||
.metadata/
|
||||
|
||||
5
.hgtags
5
.hgtags
@ -386,3 +386,8 @@ d273dfe9a126d3bffe92072547fef2cd1361b0eb jdk-9+138
|
||||
9aadd2163b568d76f8969ad2fb404a63733da359 jdk-9+141
|
||||
df0e03e3ca0ed1307793017dfc1a054c8726131c jdk-9+142
|
||||
d62173b931bf5b6bffc6e80a9060bb2e8b8efc75 jdk-9+143
|
||||
31f5023200d42185b70c4c00ba5672391e4642d0 jdk-9+144
|
||||
3ee4e7827413fa5c5c4fca58597b0ad89e921bfb jdk-9+145
|
||||
581331db696a62dd411926ba7fd437252252a71d jdk-9+146
|
||||
f4e854a77aa38749bd90f722b06974a56e7233d5 jdk-9+147
|
||||
5c71ea43933b6c7e8a85eb1a4eb2213011b95d82 jdk-9+148
|
||||
|
||||
@ -386,3 +386,8 @@ a5815c6098a241d3a1df64d22b84b3524e4a77df jdk-9+140
|
||||
f64afae7f1a5608e438585bbf0bc23785e69cba0 jdk-9+141
|
||||
2b3e5caafe3594ea507c37675c4d3086f415dc64 jdk-9+142
|
||||
1fc62b1c629fb80fdaa639d3b59452a184f0d705 jdk-9+143
|
||||
8d337fd6333e28c48aa87880144b840aad82baaf jdk-9+144
|
||||
ff98aa9ec9fae991e426ce5926fc9036d25f5562 jdk-9+145
|
||||
a22e2671d88f6b22a4aa82e3966986542ed2a381 jdk-9+146
|
||||
5f6920274c48eb00d31afee6c034826a754c13d9 jdk-9+147
|
||||
3ffc3e886c74736e387f3685e86b557cdea706c8 jdk-9+148
|
||||
|
||||
@ -1048,7 +1048,9 @@ AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS],
|
||||
# These tools might not be installed by default,
|
||||
# need hint on how to install them.
|
||||
BASIC_REQUIRE_PROGS(UNZIP, unzip)
|
||||
BASIC_REQUIRE_PROGS(ZIP, zip)
|
||||
# Since zip uses "ZIP" as a environment variable for passing options, we need
|
||||
# to name our variable differently, hence ZIPEXE.
|
||||
BASIC_REQUIRE_PROGS(ZIPEXE, zip)
|
||||
|
||||
# Non-required basic tools
|
||||
|
||||
|
||||
@ -98,7 +98,7 @@ AC_DEFUN([BOOTJDK_DO_CHECK],
|
||||
fi
|
||||
])
|
||||
|
||||
# Test: Is bootjdk explicitely set by command line arguments?
|
||||
# Test: Is bootjdk explicitly set by command line arguments?
|
||||
AC_DEFUN([BOOTJDK_CHECK_ARGUMENTS],
|
||||
[
|
||||
if test "x$with_boot_jdk" != x; then
|
||||
@ -238,7 +238,7 @@ AC_DEFUN([BOOTJDK_CHECK_TOOL_IN_BOOTJDK],
|
||||
$1=$BOOT_JDK/bin/$2
|
||||
if test ! -x [$]$1; then
|
||||
AC_MSG_RESULT(not found)
|
||||
AC_MSG_NOTICE([Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk])
|
||||
AC_MSG_NOTICE([Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk])
|
||||
AC_MSG_ERROR([Could not find $2 in the Boot JDK])
|
||||
fi
|
||||
AC_MSG_RESULT(ok)
|
||||
@ -262,7 +262,7 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK],
|
||||
# we detected something (if so, the path to the jdk is in BOOT_JDK). But we
|
||||
# must check if this is indeed valid; otherwise we'll continue looking.
|
||||
|
||||
# Test: Is bootjdk explicitely set by command line arguments?
|
||||
# Test: Is bootjdk explicitly set by command line arguments?
|
||||
BOOTJDK_DO_CHECK([BOOTJDK_CHECK_ARGUMENTS])
|
||||
if test "x$with_boot_jdk" != x && test "x$BOOT_JDK_FOUND" = xno; then
|
||||
# Having specified an argument which is incorrect will produce an instant failure;
|
||||
@ -286,7 +286,7 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK],
|
||||
if test "x$BOOT_JDK_FOUND" = xno; then
|
||||
HELP_MSG_MISSING_DEPENDENCY([openjdk])
|
||||
AC_MSG_NOTICE([Could not find a valid Boot JDK. $HELP_MSG])
|
||||
AC_MSG_NOTICE([This might be fixed by explicitely setting --with-boot-jdk])
|
||||
AC_MSG_NOTICE([This might be fixed by explicitly setting --with-boot-jdk])
|
||||
AC_MSG_ERROR([Cannot continue])
|
||||
fi
|
||||
|
||||
|
||||
@ -217,6 +217,13 @@ AC_DEFUN([BPERF_SETUP_CCACHE],
|
||||
AC_DEFUN([BPERF_SETUP_CCACHE_USAGE],
|
||||
[
|
||||
if test "x$CCACHE" != x; then
|
||||
if test "x$OPENJDK_BUILD_OS" = "xmacosx"; then
|
||||
HAS_BAD_CCACHE=[`$ECHO $CCACHE_VERSION | \
|
||||
$GREP -e '^1\.' -e '^2\.' -e '^3\.0\.' -e '^3\.1\.'`]
|
||||
if test "x$HAS_BAD_CCACHE" != "x"; then
|
||||
AC_MSG_ERROR([On macosx, ccache 3.2 or later is required, found $CCACHE_VERSION])
|
||||
fi
|
||||
fi
|
||||
if test "x$USE_PRECOMPILED_HEADER" = "x1"; then
|
||||
HAS_BAD_CCACHE=[`$ECHO $CCACHE_VERSION | \
|
||||
$GREP -e '^1.*' -e '^2.*' -e '^3\.0.*' -e '^3\.1\.[0123]$'`]
|
||||
|
||||
@ -86,73 +86,13 @@ DISABLE_WARNING_PREFIX := @BUILD_CC_DISABLE_WARNING_PREFIX@
|
||||
# Save speed and disk space by not enabling debug symbols for the buildjdk
|
||||
ENABLE_DEBUG_SYMBOLS := false
|
||||
|
||||
####################################################
|
||||
#
|
||||
# Legacy Hotspot support
|
||||
# Control wether Hotspot builds gtest tests
|
||||
BUILD_GTEST := false
|
||||
|
||||
# Legacy setting: OPT or DBG
|
||||
VARIANT := OPT
|
||||
# Legacy setting: true or false
|
||||
FASTDEBUG := false
|
||||
# Legacy setting: debugging the class files?
|
||||
DEBUG_CLASSFILES := false
|
||||
JVM_VARIANTS := server
|
||||
|
||||
# Some users still set EXTRA_*FLAGS on the make command line. Must
|
||||
# make sure to override that when building buildjdk.
|
||||
override EXTRA_CFLAGS :=
|
||||
override EXTRA_CXXFLAGS :=
|
||||
override EXTRA_LDFLAGS :=
|
||||
|
||||
# The HOSTCC/HOSTCXX is Hotspot terminology for the BUILD_CC/BUILD_CXX, i.e. the
|
||||
# compiler that produces code that can be run on the build platform.
|
||||
HOSTCC := $(BUILD_CC)
|
||||
HOSTCXX := $(BUILD_CXX)
|
||||
|
||||
# Old name for OPENJDK_TARGET_OS (aix,bsd,hpux,linux,macosx,solaris,windows etc)
|
||||
PLATFORM := $(OPENJDK_BUILD_OS)
|
||||
# 32 or 64 bit
|
||||
ARCH_DATA_MODEL := $(OPENJDK_BUILD_CPU_BITS)
|
||||
|
||||
ALT_BOOTDIR := $(BOOT_JDK)
|
||||
# Yet another name for arch used for an extra subdir below the jvm lib.
|
||||
# Uses i386 and amd64, instead of x86 and x86_64.
|
||||
LIBARCH := @OPENJDK_BUILD_CPU_LEGACY_LIB@
|
||||
# Set the cpu architecture. Some users still set ARCH on the make command line. Must
|
||||
# make sure to override that when building buildjdk.
|
||||
override ARCH := $(OPENJDK_BUILD_CPU_ARCH)
|
||||
# Legacy setting for building for a 64 bit machine.
|
||||
# If yes then this expands to _LP64 := 1
|
||||
ifeq ($(OPENJDK_BUILD_CPU_BITS), 64)
|
||||
_LP64 := 1
|
||||
endif
|
||||
|
||||
ALT_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR)
|
||||
ALT_EXPORT_PATH := $(HOTSPOT_DIST)
|
||||
|
||||
JVM_INTERPRETER := @JVM_INTERPRETER@
|
||||
ifeq ($(JVM_INTERPRETER), cpp)
|
||||
CC_INTERP=true
|
||||
endif
|
||||
|
||||
HOTSPOT_MAKE_ARGS := product docs export_product
|
||||
|
||||
# Control wether Hotspot builds gtest tests
|
||||
BUILD_GTEST := false
|
||||
|
||||
USE_PRECOMPILED_HEADER := @USE_PRECOMPILED_HEADER@
|
||||
|
||||
# Hotspot expects the variable FULL_DEBUG_SYMBOLS=1/0 to control debug symbols
|
||||
# creation.
|
||||
FULL_DEBUG_SYMBOLS := 0
|
||||
ZIP_DEBUGINFO_FILES := 0
|
||||
# Disable stripping
|
||||
STRIP_POLICY := none
|
||||
|
||||
JVM_VARIANTS := server
|
||||
JVM_VARIANT_SERVER := true
|
||||
JVM_VARIANT_CLIENT := false
|
||||
JVM_VARIANT_MINIMAL1 := false
|
||||
JVM_VARIANT_KERNEL := false
|
||||
JVM_VARIANT_ZERO := false
|
||||
JVM_VARIANT_ZEROSHARK := false
|
||||
JVM_VARIANT_CORE := false
|
||||
|
||||
@ -182,7 +182,6 @@ TOOLCHAIN_POST_DETECTION
|
||||
|
||||
# Finally do some processing after the detection phase
|
||||
TOOLCHAIN_SETUP_BUILD_COMPILERS
|
||||
TOOLCHAIN_SETUP_LEGACY
|
||||
TOOLCHAIN_MISC_CHECKS
|
||||
|
||||
# Setup the JTReg Regression Test Harness.
|
||||
|
||||
@ -311,7 +311,11 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS],
|
||||
SET_SHARED_LIBRARY_MAPFILE='-Wl,-version-script=[$]1'
|
||||
fi
|
||||
elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
|
||||
PICFLAG="-KPIC"
|
||||
if test "x$OPENJDK_TARGET_CPU" = xsparcv9; then
|
||||
PICFLAG="-xcode=pic32"
|
||||
else
|
||||
PICFLAG="-KPIC"
|
||||
fi
|
||||
C_FLAG_REORDER='-xF'
|
||||
CXX_FLAG_REORDER='-xF'
|
||||
SHARED_LIBRARY_FLAGS="-G"
|
||||
@ -838,7 +842,6 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER],
|
||||
fastdebug | slowdebug )
|
||||
$2CFLAGS_JDK="[$]$2CFLAGS_JDK $CFLAGS_DEBUG_SYMBOLS $CFLAGS_DEBUG_OPTIONS"
|
||||
$2CXXFLAGS_JDK="[$]$2CXXFLAGS_JDK $CXXFLAGS_DEBUG_SYMBOLS $CXXFLAGS_DEBUG_OPTIONS"
|
||||
JAVAC_FLAGS="$JAVAC_FLAGS -g"
|
||||
;;
|
||||
release )
|
||||
;;
|
||||
@ -894,12 +897,12 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER],
|
||||
# Set some additional per-OS defines.
|
||||
if test "x$OPENJDK_$1_OS" = xlinux; then
|
||||
$2JVM_CFLAGS="[$]$2JVM_CFLAGS -DLINUX"
|
||||
$2JVM_CFLAGS="[$]$2JVM_CFLAGS -pipe -fPIC -fno-rtti -fno-exceptions \
|
||||
$2JVM_CFLAGS="[$]$2JVM_CFLAGS -pipe $PICFLAG -fno-rtti -fno-exceptions \
|
||||
-fvisibility=hidden -fno-strict-aliasing -fno-omit-frame-pointer"
|
||||
elif test "x$OPENJDK_$1_OS" = xsolaris; then
|
||||
$2JVM_CFLAGS="[$]$2JVM_CFLAGS -DSOLARIS"
|
||||
$2JVM_CFLAGS="[$]$2JVM_CFLAGS -template=no%extdef -features=no%split_init \
|
||||
-D_Crun_inline_placement -library=%none -KPIC -mt -features=no%except"
|
||||
-D_Crun_inline_placement -library=%none $PICFLAG -mt -features=no%except"
|
||||
elif test "x$OPENJDK_$1_OS" = xmacosx; then
|
||||
$2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -D_ALLBSD_SOURCE -D_DARWIN_UNLIMITED_SELECT"
|
||||
$2JVM_CFLAGS="[$]$2JVM_CFLAGS -D_ALLBSD_SOURCE"
|
||||
@ -942,7 +945,7 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER],
|
||||
# Little endian machine uses ELFv2 ABI.
|
||||
$2JVM_CFLAGS="[$]$2JVM_CFLAGS -DABI_ELFv2"
|
||||
# Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI.
|
||||
$2JVM_CFLAGS="[$]$2JVM_CFLAGS -mcpu=power7 -mtune=power8"
|
||||
$2JVM_CFLAGS="[$]$2JVM_CFLAGS -mcpu=power8 -mtune=power8"
|
||||
fi
|
||||
elif test "x$OPENJDK_$1_CPU" = xs390x; then
|
||||
if test "x$OPENJDK_$1_OS" = xlinux; then
|
||||
@ -1310,7 +1313,7 @@ BASIC_DEFUN_NAMED([FLAGS_COMPILER_CHECK_ARGUMENTS],
|
||||
AC_MSG_CHECKING([if both compilers support "ARG_ARGUMENT"])
|
||||
supports=no
|
||||
if test "x$C_COMP_SUPPORTS" = "xyes" -a "x$CXX_COMP_SUPPORTS" = "xyes"; then supports=yes; fi
|
||||
|
||||
|
||||
AC_MSG_RESULT([$supports])
|
||||
if test "x$supports" = "xyes" ; then
|
||||
:
|
||||
@ -1375,7 +1378,7 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC],
|
||||
|
||||
AC_MSG_CHECKING([if native warnings are errors])
|
||||
if test "x$enable_warnings_as_errors" = "xyes"; then
|
||||
AC_MSG_RESULT([yes (explicitely set)])
|
||||
AC_MSG_RESULT([yes (explicitly set)])
|
||||
WARNINGS_AS_ERRORS=true
|
||||
elif test "x$enable_warnings_as_errors" = "xno"; then
|
||||
AC_MSG_RESULT([no])
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -116,7 +116,7 @@ apt_help() {
|
||||
ffi)
|
||||
PKGHANDLER_COMMAND="sudo apt-get install libffi-dev" ;;
|
||||
x11)
|
||||
PKGHANDLER_COMMAND="sudo apt-get install libX11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev" ;;
|
||||
PKGHANDLER_COMMAND="sudo apt-get install libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev" ;;
|
||||
ccache)
|
||||
PKGHANDLER_COMMAND="sudo apt-get install ccache" ;;
|
||||
dtrace)
|
||||
|
||||
@ -163,9 +163,9 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS],
|
||||
AC_SUBST(CACERTS_FILE)
|
||||
|
||||
# Enable or disable unlimited crypto
|
||||
AC_ARG_ENABLE(unlimited-crypto, [AS_HELP_STRING([--enable-unlimited-crypto],
|
||||
[Enable unlimited crypto policy @<:@disabled@:>@])],,
|
||||
[enable_unlimited_crypto=no])
|
||||
AC_ARG_ENABLE(unlimited-crypto, [AS_HELP_STRING([--disable-unlimited-crypto],
|
||||
[Disable unlimited crypto policy @<:@enabled@:>@])],,
|
||||
[enable_unlimited_crypto=yes])
|
||||
if test "x$enable_unlimited_crypto" = "xyes"; then
|
||||
UNLIMITED_CRYPTO=true
|
||||
else
|
||||
@ -265,28 +265,14 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS],
|
||||
COMPILE_WITH_DEBUG_SYMBOLS=true
|
||||
COPY_DEBUG_SYMBOLS=true
|
||||
ZIP_EXTERNAL_DEBUG_SYMBOLS=true
|
||||
|
||||
# Hotspot legacy support, not relevant with COPY_DEBUG_SYMBOLS=true
|
||||
DEBUG_BINARIES=false
|
||||
STRIP_POLICY=min_strip
|
||||
|
||||
elif test "x$NATIVE_DEBUG_SYMBOLS" = xnone; then
|
||||
COMPILE_WITH_DEBUG_SYMBOLS=false
|
||||
COPY_DEBUG_SYMBOLS=false
|
||||
ZIP_EXTERNAL_DEBUG_SYMBOLS=false
|
||||
|
||||
DEBUG_BINARIES=false
|
||||
STRIP_POLICY=no_strip
|
||||
elif test "x$NATIVE_DEBUG_SYMBOLS" = xinternal; then
|
||||
COMPILE_WITH_DEBUG_SYMBOLS=true
|
||||
COPY_DEBUG_SYMBOLS=false
|
||||
ZIP_EXTERNAL_DEBUG_SYMBOLS=false
|
||||
|
||||
# Hotspot legacy support, will turn on -g when COPY_DEBUG_SYMBOLS=false
|
||||
DEBUG_BINARIES=true
|
||||
STRIP_POLICY=no_strip
|
||||
STRIP=""
|
||||
|
||||
elif test "x$NATIVE_DEBUG_SYMBOLS" = xexternal; then
|
||||
|
||||
if test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xlinux; then
|
||||
@ -300,10 +286,6 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS],
|
||||
COMPILE_WITH_DEBUG_SYMBOLS=true
|
||||
COPY_DEBUG_SYMBOLS=true
|
||||
ZIP_EXTERNAL_DEBUG_SYMBOLS=false
|
||||
|
||||
# Hotspot legacy support, not relevant with COPY_DEBUG_SYMBOLS=true
|
||||
DEBUG_BINARIES=false
|
||||
STRIP_POLICY=min_strip
|
||||
else
|
||||
AC_MSG_ERROR([Allowed native debug symbols are: none, internal, external, zipped])
|
||||
fi
|
||||
@ -321,10 +303,6 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS],
|
||||
AC_SUBST(COMPILE_WITH_DEBUG_SYMBOLS)
|
||||
AC_SUBST(COPY_DEBUG_SYMBOLS)
|
||||
AC_SUBST(ZIP_EXTERNAL_DEBUG_SYMBOLS)
|
||||
|
||||
# Legacy values
|
||||
AC_SUBST(DEBUG_BINARIES)
|
||||
AC_SUBST(STRIP_POLICY)
|
||||
])
|
||||
|
||||
################################################################################
|
||||
|
||||
@ -110,7 +110,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
|
||||
AC_MSG_ERROR([Version string contains + but both 'BUILD' and 'OPT' are missing])
|
||||
fi
|
||||
# Stop the version part process from setting default values.
|
||||
# We still allow them to explicitely override though.
|
||||
# We still allow them to explicitly override though.
|
||||
NO_DEFAULT_VERSION_PARTS=true
|
||||
else
|
||||
AC_MSG_ERROR([--with-version-string fails to parse as a valid version string: $with_version_string])
|
||||
@ -160,11 +160,10 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
|
||||
fi
|
||||
else
|
||||
if test "x$NO_DEFAULT_VERSION_PARTS" != xtrue; then
|
||||
# Default is to calculate a string like this <timestamp>.<username>.<base dir name>
|
||||
timestamp=`$DATE '+%Y-%m-%d-%H%M%S'`
|
||||
# Default is to calculate a string like this 'adhoc.<username>.<base dir name>'
|
||||
# Outer [ ] to quote m4.
|
||||
[ basedirname=`$BASENAME "$TOPDIR" | $TR -d -c '[a-z][A-Z][0-9].-'` ]
|
||||
VERSION_OPT="$timestamp.$USERNAME.$basedirname"
|
||||
VERSION_OPT="adhoc.$USERNAME.$basedirname"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@ -35,6 +35,8 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBFFI],
|
||||
[specify directory for the libffi include files])])
|
||||
AC_ARG_WITH(libffi-lib, [AS_HELP_STRING([--with-libffi-lib],
|
||||
[specify directory for the libffi library])])
|
||||
AC_ARG_ENABLE(libffi-bundling, [AS_HELP_STRING([--enable-libffi-bundling],
|
||||
[enable bundling of libffi.so to make the built JDK runnable on more systems])])
|
||||
|
||||
if test "x$NEEDS_LIB_FFI" = xfalse; then
|
||||
if (test "x${with_libffi}" != x && test "x${with_libffi}" != xno) || \
|
||||
@ -52,6 +54,7 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBFFI],
|
||||
fi
|
||||
|
||||
if test "x${with_libffi}" != x; then
|
||||
LIBFFI_LIB_PATH="${with_libffi}/lib"
|
||||
LIBFFI_LIBS="-L${with_libffi}/lib -lffi"
|
||||
LIBFFI_CFLAGS="-I${with_libffi}/include"
|
||||
LIBFFI_FOUND=yes
|
||||
@ -61,6 +64,7 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBFFI],
|
||||
LIBFFI_FOUND=yes
|
||||
fi
|
||||
if test "x${with_libffi_lib}" != x; then
|
||||
LIBFFI_LIB_PATH="${with_libffi_lib}"
|
||||
LIBFFI_LIBS="-L${with_libffi_lib} -lffi"
|
||||
LIBFFI_FOUND=yes
|
||||
fi
|
||||
@ -109,8 +113,65 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBFFI],
|
||||
HELP_MSG_MISSING_DEPENDENCY([ffi])
|
||||
AC_MSG_ERROR([Found libffi but could not link and compile with it. $HELP_MSG])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([if libffi should be bundled])
|
||||
if test "x$enable_libffi_bundling" = "x"; then
|
||||
AC_MSG_RESULT([no])
|
||||
ENABLE_LIBFFI_BUNDLING=false
|
||||
elif test "x$enable_libffi_bundling" = "xno"; then
|
||||
AC_MSG_RESULT([no, forced])
|
||||
ENABLE_LIBFFI_BUNDLING=false
|
||||
elif test "x$enable_libffi_bundling" = "xyes"; then
|
||||
AC_MSG_RESULT([yes, forced])
|
||||
ENABLE_LIBFFI_BUNDLING=true
|
||||
else
|
||||
AC_MSG_ERROR([Invalid value for --enable-libffi-bundling])
|
||||
fi
|
||||
|
||||
# Find the libffi.so.X to bundle
|
||||
if test "x${ENABLE_LIBFFI_BUNDLING}" = "xtrue"; then
|
||||
AC_MSG_CHECKING([for libffi lib file location])
|
||||
if test "x${LIBFFI_LIB_PATH}" != x; then
|
||||
if test -e ${LIBFFI_LIB_PATH}/libffi.so.?; then
|
||||
LIBFFI_LIB_FILE="${LIBFFI_LIB_PATH}/libffi.so.?"
|
||||
else
|
||||
AC_MSG_ERROR([Could not locate libffi.so.? for bundling in ${LIBFFI_LIB_PATH}])
|
||||
fi
|
||||
else
|
||||
# If we don't have an explicit path, look in a few obvious places
|
||||
if test "x${OPENJDK_TARGET_CPU}" = "xx86"; then
|
||||
if test -e ${SYSROOT}/usr/lib/libffi.so.? ; then
|
||||
LIBFFI_LIB_FILE="${SYSROOT}/usr/lib/libffi.so.?"
|
||||
elif test -e ${SYSROOT}/usr/lib/i386-linux-gnu/libffi.so.? ; then
|
||||
LIBFFI_LIB_FILE="${SYSROOT}/usr/lib/i386-linux-gnu/libffi.so.?"
|
||||
else
|
||||
AC_MSG_ERROR([Could not locate libffi.so.? for bundling])
|
||||
fi
|
||||
elif test "x${OPENJDK_TARGET_CPU}" = "xx86_64"; then
|
||||
if test -e ${SYSROOT}/usr/lib64/libffi.so.? ; then
|
||||
LIBFFI_LIB_FILE="${SYSROOT}/usr/lib64/libffi.so.?"
|
||||
elif test -e ${SYSROOT}/usr/lib/x86_64-linux-gnu/libffi.so.? ; then
|
||||
LIBFFI_LIB_FILE="${SYSROOT}/usr/lib/x86_64-linux-gnu/libffi.so.?"
|
||||
else
|
||||
AC_MSG_ERROR([Could not locate libffi.so.? for bundling])
|
||||
fi
|
||||
else
|
||||
# Fallback on the default /usr/lib dir
|
||||
if test -e ${SYSROOT}/usr/lib/libffi.so.? ; then
|
||||
LIBFFI_LIB_FILE="${SYSROOT}/usr/lib/libffi.so.?"
|
||||
else
|
||||
AC_MSG_ERROR([Could not locate libffi.so.? for bundling])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# Make sure the wildcard is evaluated
|
||||
LIBFFI_LIB_FILE="$(ls ${LIBFFI_LIB_FILE})"
|
||||
AC_MSG_RESULT([${LIBFFI_LIB_FILE}])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(LIBFFI_CFLAGS)
|
||||
AC_SUBST(LIBFFI_LIBS)
|
||||
AC_SUBST(ENABLE_LIBFFI_BUNDLING)
|
||||
AC_SUBST(LIBFFI_LIB_FILE)
|
||||
])
|
||||
|
||||
@ -42,7 +42,7 @@ AC_DEFUN_ONCE([LIB_SETUP_X11],
|
||||
|
||||
if test "x${with_x}" != x && test "x${with_x}" != xyes; then
|
||||
# The user has specified a X11 base directory. Use it for includes and
|
||||
# libraries, unless explicitely overridden.
|
||||
# libraries, unless explicitly overridden.
|
||||
if test "x$x_includes" = xNONE; then
|
||||
x_includes="${with_x}/include"
|
||||
fi
|
||||
|
||||
@ -162,7 +162,7 @@ AC_DEFUN([PLATFORM_EXTRACT_TARGET_AND_BUILD],
|
||||
# Convert the autoconf OS/CPU value to our own data, into the VAR_OS/CPU variables.
|
||||
PLATFORM_EXTRACT_VARS_FROM_OS($build_os)
|
||||
PLATFORM_EXTRACT_VARS_FROM_CPU($build_cpu)
|
||||
# ..and setup our own variables. (Do this explicitely to facilitate searching)
|
||||
# ..and setup our own variables. (Do this explicitly to facilitate searching)
|
||||
OPENJDK_BUILD_OS="$VAR_OS"
|
||||
if test "x$VAR_OS_TYPE" != x; then
|
||||
OPENJDK_BUILD_OS_TYPE="$VAR_OS_TYPE"
|
||||
@ -192,7 +192,7 @@ AC_DEFUN([PLATFORM_EXTRACT_TARGET_AND_BUILD],
|
||||
# Convert the autoconf OS/CPU value to our own data, into the VAR_OS/CPU variables.
|
||||
PLATFORM_EXTRACT_VARS_FROM_OS($host_os)
|
||||
PLATFORM_EXTRACT_VARS_FROM_CPU($host_cpu)
|
||||
# ... and setup our own variables. (Do this explicitely to facilitate searching)
|
||||
# ... and setup our own variables. (Do this explicitly to facilitate searching)
|
||||
OPENJDK_TARGET_OS="$VAR_OS"
|
||||
if test "x$VAR_OS_TYPE" != x; then
|
||||
OPENJDK_TARGET_OS_TYPE="$VAR_OS_TYPE"
|
||||
|
||||
@ -126,6 +126,12 @@ AC_DEFUN_ONCE([SRCDIRS_SETUP_IMPORT_MODULES],
|
||||
if test -d "$IMPORT_MODULES_TOPDIR/modules_src"; then
|
||||
IMPORT_MODULES_SRC="$IMPORT_MODULES_TOPDIR/modules_src"
|
||||
fi
|
||||
# Workaround for using different imported module-info.java in Jake due to a
|
||||
# change in format. Remove once new format is standard in JDK 9 and javafx
|
||||
# delivers just that.
|
||||
if test -d "$IMPORT_MODULES_TOPDIR/modules_src_jake"; then
|
||||
IMPORT_MODULES_SRC="$IMPORT_MODULES_TOPDIR/modules_src_jake $IMPORT_MODULES_SRC"
|
||||
fi
|
||||
if test -d "$IMPORT_MODULES_TOPDIR/make"; then
|
||||
IMPORT_MODULES_MAKE="$IMPORT_MODULES_TOPDIR/make"
|
||||
fi
|
||||
|
||||
@ -319,6 +319,8 @@ ALSA_LIBS:=@ALSA_LIBS@
|
||||
ALSA_CFLAGS:=@ALSA_CFLAGS@
|
||||
LIBFFI_LIBS:=@LIBFFI_LIBS@
|
||||
LIBFFI_CFLAGS:=@LIBFFI_CFLAGS@
|
||||
ENABLE_LIBFFI_BUNDLING:=@ENABLE_LIBFFI_BUNDLING@
|
||||
LIBFFI_LIB_FILE:=@LIBFFI_LIB_FILE@
|
||||
|
||||
PACKAGE_PATH=@PACKAGE_PATH@
|
||||
|
||||
@ -657,8 +659,7 @@ TOUCH:=@TOUCH@
|
||||
UNIQ:=@UNIQ@
|
||||
WC:=@WC@
|
||||
XARGS:=@XARGS@
|
||||
ZIPEXE:=@ZIP@
|
||||
ZIP:=@ZIP@
|
||||
ZIPEXE:=@ZIPEXE@
|
||||
UNZIP:=@UNZIP@
|
||||
MT:=@FIXPATH@ @MT@
|
||||
RC:=@FIXPATH@ @RC@
|
||||
|
||||
@ -53,7 +53,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++"
|
||||
# Minimum supported versions, empty means unspecified
|
||||
TOOLCHAIN_MINIMUM_VERSION_clang="3.2"
|
||||
TOOLCHAIN_MINIMUM_VERSION_gcc="4.3"
|
||||
TOOLCHAIN_MINIMUM_VERSION_microsoft=""
|
||||
TOOLCHAIN_MINIMUM_VERSION_microsoft="16.00.30319.01" # VS2010
|
||||
TOOLCHAIN_MINIMUM_VERSION_solstudio="5.13"
|
||||
TOOLCHAIN_MINIMUM_VERSION_xlc=""
|
||||
|
||||
@ -69,15 +69,15 @@ AC_DEFUN([TOOLCHAIN_PREPARE_FOR_VERSION_COMPARISONS],
|
||||
fi
|
||||
|
||||
# We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal.
|
||||
if [ [[ "[$]$1CC_VERSION_NUMBER" =~ (.*\.){3} ]] ]; then
|
||||
AC_MSG_WARN([C compiler version number has more than three parts (X.Y.Z): [$]$1CC_VERSION_NUMBER. Comparisons might be wrong.])
|
||||
if [ [[ "[$]$1CC_VERSION_NUMBER" =~ (.*\.){4} ]] ]; then
|
||||
AC_MSG_WARN([C compiler version number has more than four parts (W.X.Y.Z): [$]$1CC_VERSION_NUMBER. Comparisons might be wrong.])
|
||||
fi
|
||||
|
||||
if [ [[ "[$]$1CC_VERSION_NUMBER" =~ [0-9]{6} ]] ]; then
|
||||
AC_MSG_WARN([C compiler version number has a part larger than 99999: [$]$1CC_VERSION_NUMBER. Comparisons might be wrong.])
|
||||
fi
|
||||
|
||||
$2COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", [$]1, [$]2, [$]3) }' <<< "[$]$1CC_VERSION_NUMBER"`
|
||||
$2COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", [$]1, [$]2, [$]3, [$]4) }' <<< "[$]$1CC_VERSION_NUMBER"`
|
||||
])
|
||||
|
||||
# Check if the configured compiler (C and C++) is of a specific version or
|
||||
@ -94,8 +94,8 @@ BASIC_DEFUN_NAMED([TOOLCHAIN_CHECK_COMPILER_VERSION],
|
||||
# Need to assign to a variable since m4 is blocked from modifying parts in [].
|
||||
REFERENCE_VERSION=ARG_VERSION
|
||||
|
||||
if [ [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ]; then
|
||||
AC_MSG_ERROR([Internal error: Cannot compare to ARG_VERSION, only three parts (X.Y.Z) is supported])
|
||||
if [ [[ "$REFERENCE_VERSION" =~ (.*\.){4} ]] ]; then
|
||||
AC_MSG_ERROR([Internal error: Cannot compare to ARG_VERSION, only four parts (W.X.Y.Z) is supported])
|
||||
fi
|
||||
|
||||
if [ [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ]; then
|
||||
@ -103,7 +103,7 @@ BASIC_DEFUN_NAMED([TOOLCHAIN_CHECK_COMPILER_VERSION],
|
||||
fi
|
||||
|
||||
# Version comparison method inspired by http://stackoverflow.com/a/24067243
|
||||
COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", [$]1, [$]2, [$]3) }' <<< "$REFERENCE_VERSION"`
|
||||
COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", [$]1, [$]2, [$]3, [$]4) }' <<< "$REFERENCE_VERSION"`
|
||||
|
||||
if test [$]ARG_PREFIX[COMPARABLE_ACTUAL_VERSION] -ge $COMPARABLE_REFERENCE_VERSION ; then
|
||||
:
|
||||
@ -333,9 +333,11 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_COMPILER_VERSION],
|
||||
if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
|
||||
# cc -V output typically looks like
|
||||
# cc: Sun C 5.12 Linux_i386 2011/11/16
|
||||
# or
|
||||
# cc: Studio 12.5 Sun C 5.14 SunOS_sparc 2016/05/31
|
||||
COMPILER_VERSION_OUTPUT=`$COMPILER -V 2>&1`
|
||||
# Check that this is likely to be the Solaris Studio cc.
|
||||
$ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.*: Sun $COMPILER_NAME" > /dev/null
|
||||
$ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.* Sun $COMPILER_NAME" > /dev/null
|
||||
if test $? -ne 0; then
|
||||
ALT_VERSION_OUTPUT=`$COMPILER --version 2>&1`
|
||||
AC_MSG_NOTICE([The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler.])
|
||||
@ -827,7 +829,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_BUILD_COMPILERS],
|
||||
BUILD_SYSROOT_CFLAGS="$SYSROOT_CFLAGS"
|
||||
BUILD_SYSROOT_LDFLAGS="$SYSROOT_LDFLAGS"
|
||||
BUILD_AR="$AR"
|
||||
|
||||
|
||||
TOOLCHAIN_PREPARE_FOR_VERSION_COMPARISONS([], [OPENJDK_BUILD_])
|
||||
fi
|
||||
|
||||
@ -842,36 +844,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_BUILD_COMPILERS],
|
||||
AC_SUBST(BUILD_AR)
|
||||
])
|
||||
|
||||
# Setup legacy variables that are still needed as alternative ways to refer to
|
||||
# parts of the toolchain.
|
||||
AC_DEFUN_ONCE([TOOLCHAIN_SETUP_LEGACY],
|
||||
[
|
||||
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
|
||||
# For hotspot, we need these in Windows mixed path,
|
||||
# so rewrite them all. Need added .exe suffix.
|
||||
HOTSPOT_CXX="$CXX.exe"
|
||||
HOTSPOT_LD="$LD.exe"
|
||||
HOTSPOT_MT="$MT.exe"
|
||||
HOTSPOT_RC="$RC.exe"
|
||||
BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH(HOTSPOT_CXX)
|
||||
BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH(HOTSPOT_LD)
|
||||
BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH(HOTSPOT_MT)
|
||||
BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH(HOTSPOT_RC)
|
||||
AC_SUBST(HOTSPOT_MT)
|
||||
AC_SUBST(HOTSPOT_RC)
|
||||
else
|
||||
HOTSPOT_CXX="$CXX"
|
||||
HOTSPOT_LD="$LD"
|
||||
fi
|
||||
AC_SUBST(HOTSPOT_CXX)
|
||||
AC_SUBST(HOTSPOT_LD)
|
||||
|
||||
if test "x$TOOLCHAIN_TYPE" = xclang; then
|
||||
USE_CLANG=true
|
||||
fi
|
||||
AC_SUBST(USE_CLANG)
|
||||
])
|
||||
|
||||
# Do some additional checks on the detected tools.
|
||||
AC_DEFUN_ONCE([TOOLCHAIN_MISC_CHECKS],
|
||||
[
|
||||
|
||||
@ -566,7 +566,7 @@ AC_DEFUN([TOOLCHAIN_SETUP_VS_RUNTIME_DLLS],
|
||||
[path to microsoft C runtime dll (msvcr*.dll) (Windows only) @<:@probed@:>@])])
|
||||
|
||||
if test "x$with_msvcr_dll" != x; then
|
||||
# If given explicitely by user, do not probe. If not present, fail directly.
|
||||
# If given explicitly by user, do not probe. If not present, fail directly.
|
||||
TOOLCHAIN_CHECK_POSSIBLE_MSVC_DLL($MSVCR_NAME, [$with_msvcr_dll], [--with-msvcr-dll])
|
||||
if test "x$MSVC_DLL" = x; then
|
||||
AC_MSG_ERROR([Could not find a proper $MSVCR_NAME as specified by --with-msvcr-dll])
|
||||
@ -589,7 +589,7 @@ AC_DEFUN([TOOLCHAIN_SETUP_VS_RUNTIME_DLLS],
|
||||
|
||||
if test "x$MSVCP_NAME" != "x"; then
|
||||
if test "x$with_msvcp_dll" != x; then
|
||||
# If given explicitely by user, do not probe. If not present, fail directly.
|
||||
# If given explicitly by user, do not probe. If not present, fail directly.
|
||||
TOOLCHAIN_CHECK_POSSIBLE_MSVC_DLL($MSVCP_NAME, [$with_msvcp_dll], [--with-msvcp-dll])
|
||||
if test "x$MSVC_DLL" = x; then
|
||||
AC_MSG_ERROR([Could not find a proper $MSVCP_NAME as specified by --with-msvcp-dll])
|
||||
|
||||
@ -372,7 +372,7 @@ compare_general_files() {
|
||||
$CAT $OTHER_DIR/$f | eval "$HTML_FILTER" > $OTHER_FILE &
|
||||
$CAT $THIS_DIR/$f | eval "$HTML_FILTER" > $THIS_FILE &
|
||||
wait
|
||||
elif [ "$f" = "./lib/classlist" ]; then
|
||||
elif [[ "$f" = *"/lib/classlist" ]]; then
|
||||
# The classlist files may have some lines in random order
|
||||
OTHER_FILE=$WORK_DIR/$f.other
|
||||
THIS_FILE=$WORK_DIR/$f.this
|
||||
@ -642,69 +642,18 @@ compare_bin_file() {
|
||||
|
||||
if [ "$OPENJDK_TARGET_OS" = "windows" ]; then
|
||||
unset _NT_SYMBOL_PATH
|
||||
# On windows we need to unzip the debug symbols, if present
|
||||
OTHER_FILE_BASE=${OTHER_FILE/.dll/}
|
||||
OTHER_FILE_BASE=${OTHER_FILE_BASE/.exe/}
|
||||
OTHER_FILE_BASE=${OTHER_FILE_BASE/.cpl/}
|
||||
DIZ_NAME=$(basename $OTHER_FILE_BASE).diz
|
||||
# Some .exe files have the same name as a .dll file. Make sure the exe
|
||||
# files get the right debug symbols.
|
||||
if [ "$NAME" = "java.exe" ] \
|
||||
&& [ -f "$OTHER/support/native/java.base/java_objs/java.diz" ]; then
|
||||
OTHER_DIZ_FILE="$OTHER/support/native/java.base/java_objs/java.diz"
|
||||
elif [ "$NAME" = "jimage.exe" ] \
|
||||
&& [ -f "$OTHER/support/native/jdk.jlink/jimage_objs/jimage.diz" ]; then
|
||||
OTHER_DIZ_FILE="$OTHER/support/modules_cmds/jdk.jlink/jimage.diz"
|
||||
elif [ "$NAME" = "javacpl.exe" ] \
|
||||
&& [ -f "$OTHER/support/native/jdk.plugin/javacpl/javacpl.diz" ]; then
|
||||
OTHER_DIZ_FILE="$OTHER/support/modules_cmds/jdk.deploy.controlpanel/javacpl.diz"
|
||||
elif [ -f "${OTHER_FILE_BASE}.diz" ]; then
|
||||
OTHER_DIZ_FILE=${OTHER_FILE_BASE}.diz
|
||||
else
|
||||
# Some files, jli.dll, appears twice in the image but only one of
|
||||
# them has a diz file next to it.
|
||||
OTHER_DIZ_FILE="$($FIND $OTHER_DIR -name $DIZ_NAME | $SED 1q)"
|
||||
if [ ! -f "$OTHER_DIZ_FILE" ]; then
|
||||
# As a last resort, look for diz file in the whole build output
|
||||
# dir.
|
||||
OTHER_DIZ_FILE="$($FIND $OTHER -name $DIZ_NAME | $SED 1q)"
|
||||
fi
|
||||
fi
|
||||
if [ -n "$OTHER_DIZ_FILE" ]; then
|
||||
$MKDIR -p $FILE_WORK_DIR/other
|
||||
(cd $FILE_WORK_DIR/other ; $UNARCHIVE -o $OTHER_DIZ_FILE)
|
||||
export _NT_SYMBOL_PATH="$FILE_WORK_DIR/other"
|
||||
fi
|
||||
|
||||
THIS_FILE_BASE=${THIS_FILE/.dll/}
|
||||
THIS_FILE_BASE=${THIS_FILE_BASE/.exe/}
|
||||
THIS_FILE_BASE=${THIS_FILE_BASE/.cpl/}
|
||||
# Some .exe files have the same name as a .dll file. Make sure the exe
|
||||
# files get the right debug symbols.
|
||||
if [ "$NAME" = "java.exe" ] \
|
||||
&& [ -f "$THIS/support/native/java.base/java_objs/java.diz" ]; then
|
||||
THIS_DIZ_FILE="$THIS/support/native/java.base/java_objs/java.diz"
|
||||
elif [ "$NAME" = "jimage.exe" ] \
|
||||
&& [ -f "$THIS/support/native/jdk.jlink/jimage_objs/jimage.diz" ]; then
|
||||
THIS_DIZ_FILE="$THIS/support/modules_cmds/jdk.jlink/jimage.diz"
|
||||
elif [ "$NAME" = "javacpl.exe" ] \
|
||||
&& [ -f "$THIS/support/native/jdk.plugin/javacpl/javacpl.diz" ]; then
|
||||
THIS_DIZ_FILE="$THIS/support/modules_cmds/jdk.deploy.controlpanel/javacpl.diz"
|
||||
elif [ -f "${THIS_FILE_BASE}.diz" ]; then
|
||||
THIS_DIZ_FILE=${THIS_FILE/.dll/}.diz
|
||||
else
|
||||
THIS_DIZ_FILE="$($FIND $THIS_DIR -name $DIZ_NAME | $SED 1q)"
|
||||
if [ ! -f "$THIS_DIZ_FILE" ]; then
|
||||
# As a last resort, look for diz file in the whole build output
|
||||
# dir.
|
||||
THIS_DIZ_FILE="$($FIND $THIS -name $DIZ_NAME | $SED 1q)"
|
||||
fi
|
||||
fi
|
||||
if [ -n "$THIS_DIZ_FILE" ]; then
|
||||
$MKDIR -p $FILE_WORK_DIR/this
|
||||
(cd $FILE_WORK_DIR/this ; $UNARCHIVE -o $THIS_DIZ_FILE)
|
||||
export _NT_SYMBOL_PATH="$_NT_SYMBOL_PATH;$FILE_WORK_DIR/this"
|
||||
if [ "$(uname -o)" = "Cygwin" ]; then
|
||||
THIS=$(cygpath -msa $THIS)
|
||||
OTHER=$(cygpath -msa $OTHER)
|
||||
fi
|
||||
# Build an _NT_SYMBOL_PATH that contains all known locations for
|
||||
# pdb files.
|
||||
PDB_DIRS="$(ls -d \
|
||||
{$OTHER,$THIS}/support/modules_{cmds,libs}/{*,*/*} \
|
||||
{$OTHER,$THIS}/support/demos/image/jvmti/*/lib \
|
||||
{$OTHER,$THIS}/support/native/java.base/java_objs \
|
||||
)"
|
||||
export _NT_SYMBOL_PATH="$(echo $PDB_DIRS | tr ' ' ';')"
|
||||
fi
|
||||
|
||||
if [ -z "$SKIP_BIN_DIFF" ]; then
|
||||
@ -1346,8 +1295,8 @@ if [ "$SKIP_DEFAULT" != "true" ]; then
|
||||
OTHER_JDK="$OTHER/images/jdk"
|
||||
OTHER_JRE="$OTHER/images/jre"
|
||||
echo "Selecting jdk images for compare"
|
||||
elif [ -d "$(ls -d $THIS/licensee-src/build/*/images/jdk)" ] \
|
||||
&& [ -d "$(ls -d $OTHER/licensee-src/build/*/images/jdk)" ]
|
||||
elif [ -d "$(ls -d $THIS/licensee-src/build/*/images/jdk 2> /dev/null)" ] \
|
||||
&& [ -d "$(ls -d $OTHER/licensee-src/build/*/images/jdk 2> /dev/null)" ]
|
||||
then
|
||||
echo "Selecting licensee images for compare"
|
||||
# Simply override the THIS and OTHER dir with the build dir from
|
||||
|
||||
@ -431,6 +431,8 @@ if [ "$OPENJDK_TARGET_OS" = "windows" ]; then
|
||||
|
||||
ACCEPTED_JARZIP_CONTENTS="
|
||||
/modules_libs/java.security.jgss/w2k_lsa_auth.diz
|
||||
/modules_libs/java.security.jgss/w2k_lsa_auth.pdb
|
||||
/modules_libs/java.security.jgss/w2k_lsa_auth.map
|
||||
/modules_libs/java.security.jgss/w2k_lsa_auth.dll
|
||||
"
|
||||
|
||||
|
||||
@ -346,6 +346,35 @@ var getJibProfilesProfiles = function (input, common) {
|
||||
// Generate debug profiles for the open jprt profiles
|
||||
profiles = concatObjects(profiles, generateDebugProfiles(common, openOnlyProfiles));
|
||||
|
||||
// Profiles for building the zero jvm variant. These are used for verification
|
||||
// in JPRT.
|
||||
var zeroProfiles = {
|
||||
"linux-x64-zero": {
|
||||
target_os: "linux",
|
||||
target_cpu: "x64",
|
||||
dependencies: concat(common.dependencies, "devkit"),
|
||||
configure_args: concat(common.configure_args,
|
||||
"--with-zlib=system",
|
||||
"--with-jvm-variants=zero",
|
||||
"--enable-libffi-bundling"),
|
||||
default_make_targets: common.default_make_targets
|
||||
},
|
||||
|
||||
"linux-x86-zero": {
|
||||
target_os: "linux",
|
||||
target_cpu: "x86",
|
||||
build_cpu: "x64",
|
||||
dependencies: concat(common.dependencies, "devkit"),
|
||||
configure_args: concat(common.configure_args, common.configure_args_32bit,
|
||||
"--with-zlib=system",
|
||||
"--with-jvm-variants=zero",
|
||||
"--enable-libffi-bundling"),
|
||||
default_make_targets: common.default_make_targets
|
||||
},
|
||||
}
|
||||
profiles = concatObjects(profiles, zeroProfiles);
|
||||
profiles = concatObjects(profiles, generateDebugProfiles(common, zeroProfiles));
|
||||
|
||||
// Profiles used to run tests. Used in JPRT.
|
||||
var testOnlyProfiles = {
|
||||
|
||||
@ -380,7 +409,7 @@ var getJibProfilesDependencies = function (input, common) {
|
||||
+ (input.build_cpu == "x86" ? "i586" : input.build_cpu);
|
||||
|
||||
var devkit_platform_revisions = {
|
||||
linux_x64: "gcc4.9.2-OEL6.4+1.0",
|
||||
linux_x64: "gcc4.9.2-OEL6.4+1.1",
|
||||
macosx_x64: "Xcode6.3-MacOSX10.9+1.0",
|
||||
solaris_x64: "SS12u4-Solaris11u1+1.0",
|
||||
solaris_sparcv9: "SS12u4-Solaris11u1+1.0",
|
||||
@ -427,7 +456,7 @@ var getJibProfilesDependencies = function (input, common) {
|
||||
jtreg: {
|
||||
server: "javare",
|
||||
revision: "4.2",
|
||||
build_number: "b03",
|
||||
build_number: "b04",
|
||||
checksum_file: "MD5_VALUES",
|
||||
file: "jtreg_bin-4.2.zip",
|
||||
environment_name: "JT_HOME",
|
||||
|
||||
@ -2,5 +2,4 @@
|
||||
^dist/
|
||||
^webrev
|
||||
/nbproject/private/
|
||||
^.hgtip
|
||||
.DS_Store
|
||||
|
||||
@ -386,3 +386,8 @@ aa053a3faf266c12b4fd5272da431a3e08e4a3e3 jdk-9+136
|
||||
b32f998da32b488ec7c4e9dbb3c750841b48e74d jdk-9+141
|
||||
408c9c621938ca028e20bced0459f815de47eba8 jdk-9+142
|
||||
6211236ef15ec796806357608b1dd1b70c258ece jdk-9+143
|
||||
d4f1dae174098e799c48948e866054c52e11a186 jdk-9+144
|
||||
a44b156ae7f06bf41b9bece30df7775e482395dd jdk-9+145
|
||||
ecd74b41ab65bf228837b5bdf99690638d55425c jdk-9+146
|
||||
dc49e0922a8e4387cbf8670bbe1dc51c9874b74b jdk-9+147
|
||||
f95cc86b6ac22ec1ade5d4f825dc7782adeea228 jdk-9+148
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,9 +26,10 @@
|
||||
/**
|
||||
* Defines the Java binding of the OMG CORBA APIs, and the RMI-IIOP API.
|
||||
*/
|
||||
@Deprecated(since="9", forRemoval=true)
|
||||
module java.corba {
|
||||
requires public java.desktop;
|
||||
requires public java.rmi;
|
||||
requires transitive java.desktop;
|
||||
requires transitive java.rmi;
|
||||
requires java.logging;
|
||||
requires java.naming;
|
||||
requires java.transaction;
|
||||
@ -65,14 +66,13 @@ module java.corba {
|
||||
exports org.omg.PortableServer.portable;
|
||||
exports org.omg.SendingContext;
|
||||
exports org.omg.stub.java.rmi;
|
||||
exports com.sun.corba.se.impl.util to
|
||||
jdk.rmic;
|
||||
exports com.sun.jndi.cosnaming to
|
||||
java.naming;
|
||||
exports com.sun.jndi.url.corbaname to
|
||||
java.naming;
|
||||
exports com.sun.jndi.url.iiop to
|
||||
java.naming;
|
||||
exports com.sun.jndi.url.iiopname to
|
||||
java.naming;
|
||||
|
||||
// rmic --iiop
|
||||
exports com.sun.corba.se.impl.util to jdk.rmic;
|
||||
|
||||
// JNDI CosNaming provider
|
||||
opens com.sun.jndi.cosnaming to java.naming; // jndiprovider.properties
|
||||
exports com.sun.jndi.url.corbaname to java.naming;
|
||||
exports com.sun.jndi.url.iiop to java.naming;
|
||||
exports com.sun.jndi.url.iiopname to java.naming;
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
^src/share/tools/IdealGraphVisualizer/dist/
|
||||
^src/share/tools/IdealGraphVisualizer/nbplatform/
|
||||
.igv.log
|
||||
^.hgtip
|
||||
.DS_Store
|
||||
^\.mx.jvmci/env
|
||||
^\.mx.jvmci/.*\.pyc
|
||||
@ -24,3 +23,19 @@
|
||||
^test/compiler/jvmci/\w[\w\.]*/.*\.iml
|
||||
^test/compiler/jvmci/\w[\w\.]*/nbproject
|
||||
^test/compiler/jvmci/\w[\w\.]*/\..*
|
||||
^test/compiler/aot/\w[\w\.]*/.*\.xml
|
||||
^test/compiler/aot/\w[\w\.]*/.*\.iml
|
||||
^test/compiler/aot/\w[\w\.]*/nbproject
|
||||
^test/compiler/aot/\w[\w\.]*/\..*
|
||||
^src/jdk.vm.compiler/\.mx.graal/env
|
||||
^src/jdk.vm.compiler/\.mx.graal/.*\.pyc
|
||||
^src/jdk.vm.compiler/\.mx.graal/eclipse-launches/.*
|
||||
^src/jdk.aot/share/classes/\w[\w\.]*/.*\.xml
|
||||
^src/jdk.aot/share/classes/\w[\w\.]*/.*\.iml
|
||||
^src/jdk.aot/share/classes/\w[\w\.]*/nbproject
|
||||
^src/jdk.aot/share/classes/\w[\w\.]*/\..*
|
||||
^src/jdk.vm.compiler/share/classes/\w[\w\.]*/.*\.xml
|
||||
^src/jdk.vm.compiler/share/classes/\w[\w\.]*/.*\.iml
|
||||
^src/jdk.vm.compiler/share/classes/\w[\w\.]*/nbproject
|
||||
^src/jdk.vm.compiler/share/classes/\w[\w\.]*/\..*
|
||||
|
||||
|
||||
@ -546,3 +546,8 @@ fec31089c2ef5a12dd64f401b0bf2e00f56ee0d0 jdk-9+140
|
||||
160a00bc6ed0af1fdf8418fc65e6bddbbc0c536d jdk-9+141
|
||||
7b48d63dfd6b8e2657288de3d7b1f153dee02d7e jdk-9+142
|
||||
d87d5d430c42342f0320ca7f5cbe0cbd1f9d62ba jdk-9+143
|
||||
6187b582d02aee38341dc8ce4011906e9b364e9f jdk-9+144
|
||||
61e7ea56312351657e69198c503a6f7bf865af83 jdk-9+145
|
||||
a82cb5350cad96a0b4de496afebe3ded89f27efa jdk-9+146
|
||||
132a72c782071cc11ab25cc7c9ee167c3632fea4 jdk-9+147
|
||||
5e4e893520ecdbd517c6ed6375f0885664fe62c4 jdk-9+148
|
||||
|
||||
162
hotspot/make/CompileTools.gmk
Normal file
162
hotspot/make/CompileTools.gmk
Normal file
@ -0,0 +1,162 @@
|
||||
#
|
||||
# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# This must be the first rule
|
||||
default: all
|
||||
|
||||
include $(SPEC)
|
||||
include MakeBase.gmk
|
||||
|
||||
include JavaCompilation.gmk
|
||||
include SetupJavaCompilers.gmk
|
||||
|
||||
TARGETS :=
|
||||
|
||||
# Hook to include the corresponding custom file, if present.
|
||||
$(eval $(call IncludeCustomExtension, hotspot, CompileTools.gmk))
|
||||
|
||||
ifeq ($(INCLUDE_GRAAL), true)
|
||||
VM_CI_SRC_DIR := $(HOTSPOT_TOPDIR)/src/jdk.vm.ci/share/classes
|
||||
|
||||
SRC_DIR := $(HOTSPOT_TOPDIR)/src/jdk.vm.compiler/share/classes
|
||||
|
||||
##############################################################################
|
||||
# Compile the annotation processors
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_MATCH_PROCESSOR, \
|
||||
SETUP := GENERATE_OLDBYTECODE, \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.common/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.common/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.collections/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.asm/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.bytecode/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.code/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.debug/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.graph/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.lir/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.loop/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.loop.phases/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.nodes/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.options/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.phases/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.phases.common/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.virtual/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.runtime/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \
|
||||
, \
|
||||
EXCLUDE_FILES := $(EXCLUDE_FILES), \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor.jar, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_VM_COMPILER_MATCH_PROCESSOR)
|
||||
|
||||
##############################################################################
|
||||
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_NODEINFO_PROCESSOR, \
|
||||
SETUP := GENERATE_OLDBYTECODE, \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.nodeinfo.processor/src \
|
||||
, \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.nodeinfo.processor, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.nodeinfo.processor.jar, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_VM_COMPILER_NODEINFO_PROCESSOR)
|
||||
|
||||
##############################################################################
|
||||
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_OPTIONS_PROCESSOR, \
|
||||
SETUP := GENERATE_OLDBYTECODE, \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.options/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.options.processor/src \
|
||||
, \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor.jar, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_VM_COMPILER_OPTIONS_PROCESSOR)
|
||||
|
||||
##############################################################################
|
||||
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER, \
|
||||
SETUP := GENERATE_OLDBYTECODE, \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.common/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.collections/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.code/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.common/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.debug/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.graph/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.options/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.runtime/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \
|
||||
, \
|
||||
EXCLUDE_FILES := $(EXCLUDE_FILES), \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier.jar, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER)
|
||||
|
||||
##############################################################################
|
||||
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_SERVICEPROVIDER_PROCESSOR, \
|
||||
SETUP := GENERATE_OLDBYTECODE, \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.serviceprovider.processor/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \
|
||||
, \
|
||||
EXCLUDE_FILES := $(EXCLUDE_FILES), \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor.jar, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_VM_COMPILER_SERVICEPROVIDER_PROCESSOR)
|
||||
|
||||
##############################################################################
|
||||
endif
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
.PHONY: all
|
||||
@ -65,3 +65,17 @@ $(INCLUDE_DST_DIR)/$(JNI_MD_SUBDIR)/jni_md.h: $(JNI_MD_H_SRC)
|
||||
#TARGETS += $(INCLUDE_DST_DIR)/$(JNI_MD_SUBDIR)/jni_md.h
|
||||
|
||||
################################################################################
|
||||
# Optionally copy libffi.so.? into the the image
|
||||
|
||||
ifeq ($(ENABLE_LIBFFI_BUNDLING), true)
|
||||
$(eval $(call SetupCopyFiles, COPY_LIBFFI, \
|
||||
FILES := $(LIBFFI_LIB_FILE), \
|
||||
DEST := $(call FindLibDirForModule, $(MODULE)), \
|
||||
FLATTEN := true, \
|
||||
MACRO := install-file-nolink, \
|
||||
))
|
||||
|
||||
TARGETS += $(COPY_LIBFFI)
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
|
||||
152
hotspot/make/gensrc/Gensrc-jdk.vm.compiler.gmk
Normal file
152
hotspot/make/gensrc/Gensrc-jdk.vm.compiler.gmk
Normal file
@ -0,0 +1,152 @@
|
||||
#
|
||||
# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
default: all
|
||||
|
||||
include $(SPEC)
|
||||
include MakeBase.gmk
|
||||
|
||||
$(eval $(call IncludeCustomExtension, hotspot, gensrc/Gensrc-jdk.vm.compiler.gmk))
|
||||
|
||||
GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)
|
||||
SRC_DIR := $(HOTSPOT_TOPDIR)/src/$(MODULE)/share/classes
|
||||
|
||||
################################################################################
|
||||
|
||||
PROC_SRC_SUBDIRS := \
|
||||
org.graalvm.compiler.code \
|
||||
org.graalvm.compiler.common \
|
||||
org.graalvm.compiler.core \
|
||||
org.graalvm.compiler.core.aarch64 \
|
||||
org.graalvm.compiler.core.amd64 \
|
||||
org.graalvm.compiler.core.common \
|
||||
org.graalvm.compiler.core.sparc \
|
||||
org.graalvm.compiler.debug \
|
||||
org.graalvm.compiler.hotspot \
|
||||
org.graalvm.compiler.hotspot.aarch64 \
|
||||
org.graalvm.compiler.hotspot.amd64 \
|
||||
org.graalvm.compiler.hotspot.sparc \
|
||||
org.graalvm.compiler.graph \
|
||||
org.graalvm.compiler.java \
|
||||
org.graalvm.compiler.lir \
|
||||
org.graalvm.compiler.lir.amd64 \
|
||||
org.graalvm.compiler.loop \
|
||||
org.graalvm.compiler.loop.phases \
|
||||
org.graalvm.compiler.nodes \
|
||||
org.graalvm.compiler.replacements \
|
||||
org.graalvm.compiler.replacements.aarch64 \
|
||||
org.graalvm.compiler.replacements.amd64 \
|
||||
org.graalvm.compiler.phases \
|
||||
org.graalvm.compiler.phases.common \
|
||||
org.graalvm.compiler.printer \
|
||||
org.graalvm.compiler.virtual \
|
||||
#
|
||||
|
||||
PROC_SRC_DIRS := $(patsubst %, $(SRC_DIR)/%/src, $(PROC_SRC_SUBDIRS))
|
||||
|
||||
PROC_SRCS := $(filter %.java, $(call CacheFind, $(PROC_SRC_DIRS)))
|
||||
|
||||
ALL_SRC_DIRS := $(wildcard $(SRC_DIR)/*/src)
|
||||
SOURCEPATH := $(call PathList, $(ALL_SRC_DIRS))
|
||||
|
||||
PROCESSOR_JARS := \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor.jar \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.nodeinfo.processor.jar \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor.jar \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier.jar \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor.jar \
|
||||
#
|
||||
PROCESSOR_PATH := $(call PathList, $(PROCESSOR_JARS))
|
||||
|
||||
ADD_EXPORTS := \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.aarch64=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.amd64=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.code=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.code.site=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.code.stack=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.common=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.hotspot=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.hotspot.aarch64=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.hotspot.amd64=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.hotspot.events=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.hotspot.sparc=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.hotspotvmconfig=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.inittimer=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.meta=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.runtime=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.services=ALL-UNNAMED \
|
||||
--add-exports jdk.vm.ci/jdk.vm.ci.sparc=ALL-UNNAMED \
|
||||
#
|
||||
|
||||
$(GENSRC_DIR)/_gensrc_proc_done: $(PROC_SRCS) $(PROCESSOR_JARS)
|
||||
$(call MakeDir, $(@D))
|
||||
$(eval $(call ListPathsSafely,PROC_SRCS,$(@D)/_gensrc_proc_files))
|
||||
$(JAVA_SMALL) $(NEW_JAVAC) \
|
||||
-XDignore.symbol.file \
|
||||
--upgrade-module-path $(JDK_OUTPUTDIR)/modules --system none \
|
||||
$(ADD_EXPORTS) \
|
||||
-sourcepath $(SOURCEPATH) \
|
||||
-implicit:none \
|
||||
-proc:only \
|
||||
-processorpath $(PROCESSOR_PATH) \
|
||||
-d $(GENSRC_DIR) \
|
||||
-s $(GENSRC_DIR) \
|
||||
@$(@D)/_gensrc_proc_files
|
||||
$(TOUCH) $@
|
||||
|
||||
TARGETS += $(GENSRC_DIR)/_gensrc_proc_done
|
||||
|
||||
################################################################################
|
||||
|
||||
$(GENSRC_DIR)/module-info.java.extra: $(GENSRC_DIR)/_gensrc_proc_done
|
||||
($(CD) $(GENSRC_DIR)/META-INF/providers && \
|
||||
p=""; \
|
||||
for i in $$($(LS)); do \
|
||||
c=$$($(CAT) $$i | $(TR) -d '\n\r'); \
|
||||
if test x$$p != x$$c; then \
|
||||
if test x$$p != x; then \
|
||||
$(ECHO) " ;" >> $@; \
|
||||
fi; \
|
||||
$(ECHO) "provides $$c with" >> $@; \
|
||||
p=$$c; \
|
||||
fi; \
|
||||
$(ECHO) " $$i," >> $@; \
|
||||
done); \
|
||||
$(ECHO) " ;" >> $@; \
|
||||
$(ECHO) "uses org.graalvm.compiler.options.OptionDescriptors;" >> $@; \
|
||||
$(ECHO) "provides org.graalvm.compiler.options.OptionDescriptors with" >> $@; \
|
||||
for i in $$($(FIND) $(GENSRC_DIR) -name '*_OptionDescriptors.java'); do \
|
||||
c=$$($(ECHO) $$i | $(SED) 's:.*/jdk\.vm\.compiler/\(.*\)\.java:\1:' | $(TR) '/' '.'); \
|
||||
$(ECHO) " $$c," >> $@; \
|
||||
done; \
|
||||
$(ECHO) " ;" >> $@;
|
||||
|
||||
TARGETS += $(GENSRC_DIR)/module-info.java.extra
|
||||
|
||||
################################################################################
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
.PHONY: default all
|
||||
@ -130,8 +130,6 @@ $(JVMTI_OUTPUTDIR)/jvmtiEnvRecommended.cpp: $(JVMTI_SRCDIR)/jvmtiEnv.cpp \
|
||||
TARGETS += $(JVMTI_OUTPUTDIR)/jvmtiEnvRecommended.cpp
|
||||
|
||||
################################################################################
|
||||
# Disable copy of jvmti.h from hotspot until this has been cleared up. The file
|
||||
# is currently being copied from the jdk repository. See JDK-8167078.
|
||||
# Copy jvmti.h to include dir
|
||||
|
||||
# The file is the same regardless of jvm variant. Only let one do the copy.
|
||||
|
||||
@ -135,7 +135,7 @@ ifneq ($(OPENJDK_TARGET_OS), windows)
|
||||
ifeq ($(ZIP_EXTERNAL_DEBUG_SYMBOLS), true)
|
||||
$(LIB_OUTPUTDIR)/$1/$(LIBRARY_PREFIX)jsig.diz: \
|
||||
$(LIB_OUTPUTDIR)/$1/$(LIBRARY_PREFIX)jsig$(DEBUG_INFO_SUFFIX)
|
||||
$(CD) $$(@D) && $(ZIP) -q -y $$@ $$(basename $$(@F))$(DEBUG_INFO_SUFFIX)
|
||||
$(CD) $$(@D) && $(ZIPEXE) -q -y $$@ $$(basename $$(@F))$(DEBUG_INFO_SUFFIX)
|
||||
|
||||
TARGETS += $(LIB_OUTPUTDIR)/$1/$(LIBRARY_PREFIX)jsig.diz
|
||||
endif
|
||||
|
||||
@ -146,3 +146,11 @@ ifneq ($(call check-jvm-feature, nmt), true)
|
||||
memBaseline.cpp memReporter.cpp mallocTracker.cpp virtualMemoryTracker.cpp nmtCommon.cpp \
|
||||
memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp
|
||||
endif
|
||||
|
||||
ifeq ($(call check-jvm-feature, aot), true)
|
||||
JVM_CFLAGS_FEATURES += -DINCLUDE_AOT
|
||||
else
|
||||
JVM_EXCLUDE_FILES += \
|
||||
compiledIC_aot_x86_64.cpp compilerRuntime.cpp \
|
||||
aotCodeHeap.cpp aotCompiledMethod.cpp aotLoader.cpp compiledIC_aot.cpp
|
||||
endif
|
||||
|
||||
53
hotspot/make/lib/Lib-jdk.aot.gmk
Normal file
53
hotspot/make/lib/Lib-jdk.aot.gmk
Normal file
@ -0,0 +1,53 @@
|
||||
#
|
||||
# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
include $(SPEC)
|
||||
include NativeCompilation.gmk
|
||||
|
||||
$(eval $(call IncludeCustomExtension, hotspot, lib/Lib-jdk.aot.gmk))
|
||||
|
||||
##############################################################################
|
||||
# Build libjelfshim only when AOT is enabled.
|
||||
ifeq ($(ENABLE_AOT), true)
|
||||
JELFSHIM_NAME := jelfshim
|
||||
|
||||
$(eval $(call SetupNativeCompilation, BUILD_LIBJELFSHIM, \
|
||||
TOOLCHAIN := TOOLCHAIN_DEFAULT, \
|
||||
OPTIMIZATION := LOW, \
|
||||
LIBRARY := $(JELFSHIM_NAME), \
|
||||
OUTPUT_DIR := $(call FindLibDirForModule, $(MODULE)), \
|
||||
SRC := $(HOTSPOT_TOPDIR)/src/jdk.aot/unix/native/libjelfshim, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) $(ELF_CFLAGS) \
|
||||
-DAOT_VERSION_STRING='"$(VERSION_STRING)"' \
|
||||
-I$(SUPPORT_OUTPUTDIR)/headers/$(MODULE), \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB), \
|
||||
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/lib$(JELFSHIM_NAME), \
|
||||
LIBS := $(ELF_LIBS) $(LIBS_JDKLIB), \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_LIBJELFSHIM)
|
||||
endif
|
||||
|
||||
##############################################################################
|
||||
@ -190,8 +190,6 @@ JVM_AddModuleExportsToAll
|
||||
JVM_AddModuleExportsToAllUnnamed
|
||||
JVM_AddModulePackage
|
||||
JVM_AddReadsModule
|
||||
JVM_CanReadModule
|
||||
JVM_DefineModule
|
||||
JVM_IsExportedToModule
|
||||
JVM_SetBootLoaderUnnamedModule
|
||||
JVM_GetModuleByPackageName
|
||||
|
||||
@ -54,6 +54,9 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \
|
||||
$(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \
|
||||
$(HOTSPOT_TOPDIR)/test/compiler/calls \
|
||||
$(HOTSPOT_TOPDIR)/test/serviceability/jvmti/GetNamedModule \
|
||||
$(HOTSPOT_TOPDIR)/test/serviceability/jvmti/AddModuleReads \
|
||||
$(HOTSPOT_TOPDIR)/test/serviceability/jvmti/AddModuleExportsAndOpens \
|
||||
$(HOTSPOT_TOPDIR)/test/serviceability/jvmti/AddModuleUsesAndProvides \
|
||||
$(HOTSPOT_TOPDIR)/test/testlibrary/jvmti \
|
||||
$(HOTSPOT_TOPDIR)/test/compiler/jvmci/jdk.vm.ci.code.test \
|
||||
$(HOTSPOT_TOPDIR)/test/serviceability/jvmti/GetModulesInfo \
|
||||
@ -80,6 +83,9 @@ ifeq ($(TOOLCHAIN_TYPE), solstudio)
|
||||
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_liboverflow := -lc
|
||||
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libSimpleClassFileLoadHook := -lc
|
||||
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libGetNamedModuleTest := -lc
|
||||
BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libAddModuleReadsTest := -lc
|
||||
BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libAddModuleExportsAndOpensTest := -lc
|
||||
BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libAddModuleUsesAndProvidesTest := -lc
|
||||
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMAAClassFileLoadHook := -lc
|
||||
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMAAClassLoadPrepare := -lc
|
||||
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMAAThreadStart := -lc
|
||||
|
||||
@ -12997,137 +12997,146 @@ instruct mulD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{
|
||||
ins_pipe(fp_dop_reg_reg_d);
|
||||
%}
|
||||
|
||||
// We cannot use these fused mul w add/sub ops because they don't
|
||||
// produce the same result as the equivalent separated ops
|
||||
// (essentially they don't round the intermediate result). that's a
|
||||
// shame. leaving them here in case we can idenitfy cases where it is
|
||||
// legitimate to use them
|
||||
// src1 * src2 + src3
|
||||
instruct maddF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
|
||||
predicate(UseFMA);
|
||||
match(Set dst (FmaF src3 (Binary src1 src2)));
|
||||
|
||||
format %{ "fmadds $dst, $src1, $src2, $src3" %}
|
||||
|
||||
// instruct maddF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
|
||||
// match(Set dst (AddF (MulF src1 src2) src3));
|
||||
ins_encode %{
|
||||
__ fmadds(as_FloatRegister($dst$$reg),
|
||||
as_FloatRegister($src1$$reg),
|
||||
as_FloatRegister($src2$$reg),
|
||||
as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
|
||||
// format %{ "fmadds $dst, $src1, $src2, $src3" %}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// ins_encode %{
|
||||
// __ fmadds(as_FloatRegister($dst$$reg),
|
||||
// as_FloatRegister($src1$$reg),
|
||||
// as_FloatRegister($src2$$reg),
|
||||
// as_FloatRegister($src3$$reg));
|
||||
// %}
|
||||
// src1 * src2 + src3
|
||||
instruct maddD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{
|
||||
predicate(UseFMA);
|
||||
match(Set dst (FmaD src3 (Binary src1 src2)));
|
||||
|
||||
// ins_pipe(pipe_class_default);
|
||||
// %}
|
||||
format %{ "fmaddd $dst, $src1, $src2, $src3" %}
|
||||
|
||||
// instruct maddD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{
|
||||
// match(Set dst (AddD (MulD src1 src2) src3));
|
||||
ins_encode %{
|
||||
__ fmaddd(as_FloatRegister($dst$$reg),
|
||||
as_FloatRegister($src1$$reg),
|
||||
as_FloatRegister($src2$$reg),
|
||||
as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
|
||||
// format %{ "fmaddd $dst, $src1, $src2, $src3" %}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// ins_encode %{
|
||||
// __ fmaddd(as_FloatRegister($dst$$reg),
|
||||
// as_FloatRegister($src1$$reg),
|
||||
// as_FloatRegister($src2$$reg),
|
||||
// as_FloatRegister($src3$$reg));
|
||||
// %}
|
||||
// -src1 * src2 + src3
|
||||
instruct msubF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
|
||||
predicate(UseFMA);
|
||||
match(Set dst (FmaF src3 (Binary (NegF src1) src2)));
|
||||
match(Set dst (FmaF src3 (Binary src1 (NegF src2))));
|
||||
|
||||
// ins_pipe(pipe_class_default);
|
||||
// %}
|
||||
format %{ "fmsubs $dst, $src1, $src2, $src3" %}
|
||||
|
||||
// instruct msubF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
|
||||
// match(Set dst (AddF (MulF (NegF src1) src2) src3));
|
||||
// match(Set dst (AddF (NegF (MulF src1 src2)) src3));
|
||||
ins_encode %{
|
||||
__ fmsubs(as_FloatRegister($dst$$reg),
|
||||
as_FloatRegister($src1$$reg),
|
||||
as_FloatRegister($src2$$reg),
|
||||
as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
|
||||
// format %{ "fmsubs $dst, $src1, $src2, $src3" %}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// ins_encode %{
|
||||
// __ fmsubs(as_FloatRegister($dst$$reg),
|
||||
// as_FloatRegister($src1$$reg),
|
||||
// as_FloatRegister($src2$$reg),
|
||||
// as_FloatRegister($src3$$reg));
|
||||
// %}
|
||||
// -src1 * src2 + src3
|
||||
instruct msubD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{
|
||||
predicate(UseFMA);
|
||||
match(Set dst (FmaD src3 (Binary (NegD src1) src2)));
|
||||
match(Set dst (FmaD src3 (Binary src1 (NegD src2))));
|
||||
|
||||
// ins_pipe(pipe_class_default);
|
||||
// %}
|
||||
format %{ "fmsubd $dst, $src1, $src2, $src3" %}
|
||||
|
||||
// instruct msubD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{
|
||||
// match(Set dst (AddD (MulD (NegD src1) src2) src3));
|
||||
// match(Set dst (AddD (NegD (MulD src1 src2)) src3));
|
||||
ins_encode %{
|
||||
__ fmsubd(as_FloatRegister($dst$$reg),
|
||||
as_FloatRegister($src1$$reg),
|
||||
as_FloatRegister($src2$$reg),
|
||||
as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
|
||||
// format %{ "fmsubd $dst, $src1, $src2, $src3" %}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// ins_encode %{
|
||||
// __ fmsubd(as_FloatRegister($dst$$reg),
|
||||
// as_FloatRegister($src1$$reg),
|
||||
// as_FloatRegister($src2$$reg),
|
||||
// as_FloatRegister($src3$$reg));
|
||||
// %}
|
||||
// -src1 * src2 - src3
|
||||
instruct mnaddF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
|
||||
predicate(UseFMA);
|
||||
match(Set dst (FmaF (NegF src3) (Binary (NegF src1) src2)));
|
||||
match(Set dst (FmaF (NegF src3) (Binary src1 (NegF src2))));
|
||||
|
||||
// ins_pipe(pipe_class_default);
|
||||
// %}
|
||||
format %{ "fnmadds $dst, $src1, $src2, $src3" %}
|
||||
|
||||
// instruct mnaddF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
|
||||
// match(Set dst (SubF (MulF (NegF src1) src2) src3));
|
||||
// match(Set dst (SubF (NegF (MulF src1 src2)) src3));
|
||||
ins_encode %{
|
||||
__ fnmadds(as_FloatRegister($dst$$reg),
|
||||
as_FloatRegister($src1$$reg),
|
||||
as_FloatRegister($src2$$reg),
|
||||
as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
|
||||
// format %{ "fnmadds $dst, $src1, $src2, $src3" %}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// ins_encode %{
|
||||
// __ fnmadds(as_FloatRegister($dst$$reg),
|
||||
// as_FloatRegister($src1$$reg),
|
||||
// as_FloatRegister($src2$$reg),
|
||||
// as_FloatRegister($src3$$reg));
|
||||
// %}
|
||||
// -src1 * src2 - src3
|
||||
instruct mnaddD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{
|
||||
predicate(UseFMA);
|
||||
match(Set dst (FmaD (NegD src3) (Binary (NegD src1) src2)));
|
||||
match(Set dst (FmaD (NegD src3) (Binary src1 (NegD src2))));
|
||||
|
||||
// ins_pipe(pipe_class_default);
|
||||
// %}
|
||||
format %{ "fnmaddd $dst, $src1, $src2, $src3" %}
|
||||
|
||||
// instruct mnaddD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{
|
||||
// match(Set dst (SubD (MulD (NegD src1) src2) src3));
|
||||
// match(Set dst (SubD (NegD (MulD src1 src2)) src3));
|
||||
ins_encode %{
|
||||
__ fnmaddd(as_FloatRegister($dst$$reg),
|
||||
as_FloatRegister($src1$$reg),
|
||||
as_FloatRegister($src2$$reg),
|
||||
as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
|
||||
// format %{ "fnmaddd $dst, $src1, $src2, $src3" %}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// ins_encode %{
|
||||
// __ fnmaddd(as_FloatRegister($dst$$reg),
|
||||
// as_FloatRegister($src1$$reg),
|
||||
// as_FloatRegister($src2$$reg),
|
||||
// as_FloatRegister($src3$$reg));
|
||||
// %}
|
||||
// src1 * src2 - src3
|
||||
instruct mnsubF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3, immF0 zero) %{
|
||||
predicate(UseFMA);
|
||||
match(Set dst (FmaF (NegF src3) (Binary src1 src2)));
|
||||
|
||||
// ins_pipe(pipe_class_default);
|
||||
// %}
|
||||
format %{ "fnmsubs $dst, $src1, $src2, $src3" %}
|
||||
|
||||
// instruct mnsubF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3, immF0 zero) %{
|
||||
// match(Set dst (SubF (MulF src1 src2) src3));
|
||||
ins_encode %{
|
||||
__ fnmsubs(as_FloatRegister($dst$$reg),
|
||||
as_FloatRegister($src1$$reg),
|
||||
as_FloatRegister($src2$$reg),
|
||||
as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
|
||||
// format %{ "fnmsubs $dst, $src1, $src2, $src3" %}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// ins_encode %{
|
||||
// __ fnmsubs(as_FloatRegister($dst$$reg),
|
||||
// as_FloatRegister($src1$$reg),
|
||||
// as_FloatRegister($src2$$reg),
|
||||
// as_FloatRegister($src3$$reg));
|
||||
// %}
|
||||
// src1 * src2 - src3
|
||||
instruct mnsubD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3, immD0 zero) %{
|
||||
predicate(UseFMA);
|
||||
match(Set dst (FmaD (NegD src3) (Binary src1 src2)));
|
||||
|
||||
// ins_pipe(pipe_class_default);
|
||||
// %}
|
||||
format %{ "fnmsubd $dst, $src1, $src2, $src3" %}
|
||||
|
||||
// instruct mnsubD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3, immD0 zero) %{
|
||||
// match(Set dst (SubD (MulD src1 src2) src3));
|
||||
ins_encode %{
|
||||
// n.b. insn name should be fnmsubd
|
||||
__ fnmsub(as_FloatRegister($dst$$reg),
|
||||
as_FloatRegister($src1$$reg),
|
||||
as_FloatRegister($src2$$reg),
|
||||
as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
|
||||
// format %{ "fnmsubd $dst, $src1, $src2, $src3" %}
|
||||
|
||||
// ins_encode %{
|
||||
// // n.b. insn name should be fnmsubd
|
||||
// __ fnmsub(as_FloatRegister($dst$$reg),
|
||||
// as_FloatRegister($src1$$reg),
|
||||
// as_FloatRegister($src2$$reg),
|
||||
// as_FloatRegister($src3$$reg));
|
||||
// %}
|
||||
|
||||
// ins_pipe(pipe_class_default);
|
||||
// %}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
|
||||
instruct divF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
|
||||
|
||||
@ -65,7 +65,9 @@ bool AbstractInterpreter::can_be_compiled(methodHandle m) {
|
||||
case Interpreter::java_lang_math_log10 : // fall thru
|
||||
case Interpreter::java_lang_math_sqrt : // fall thru
|
||||
case Interpreter::java_lang_math_pow : // fall thru
|
||||
case Interpreter::java_lang_math_exp :
|
||||
case Interpreter::java_lang_math_exp : // fall thru
|
||||
case Interpreter::java_lang_math_fmaD : // fall thru
|
||||
case Interpreter::java_lang_math_fmaF :
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
|
||||
@ -375,7 +375,7 @@ int LIR_Assembler::emit_exception_handler() {
|
||||
__ nop();
|
||||
|
||||
// generate code for exception handler
|
||||
address handler_base = __ start_a_stub(exception_handler_size);
|
||||
address handler_base = __ start_a_stub(exception_handler_size());
|
||||
if (handler_base == NULL) {
|
||||
// not enough space left for the handler
|
||||
bailout("exception handler overflow");
|
||||
@ -393,7 +393,7 @@ int LIR_Assembler::emit_exception_handler() {
|
||||
|
||||
// search an exception handler (r0: exception oop, r3: throwing pc)
|
||||
__ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id))); __ should_not_reach_here();
|
||||
guarantee(code_offset() - offset <= exception_handler_size, "overflow");
|
||||
guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
|
||||
__ end_a_stub();
|
||||
|
||||
return offset;
|
||||
@ -467,7 +467,7 @@ int LIR_Assembler::emit_deopt_handler() {
|
||||
__ nop();
|
||||
|
||||
// generate code for exception handler
|
||||
address handler_base = __ start_a_stub(deopt_handler_size);
|
||||
address handler_base = __ start_a_stub(deopt_handler_size());
|
||||
if (handler_base == NULL) {
|
||||
// not enough space left for the handler
|
||||
bailout("deopt handler overflow");
|
||||
@ -478,7 +478,7 @@ int LIR_Assembler::emit_deopt_handler() {
|
||||
|
||||
__ adr(lr, pc());
|
||||
__ far_jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
|
||||
guarantee(code_offset() - offset <= deopt_handler_size, "overflow");
|
||||
guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
|
||||
__ end_a_stub();
|
||||
|
||||
return offset;
|
||||
@ -1055,7 +1055,7 @@ int LIR_Assembler::array_element_size(BasicType type) const {
|
||||
return exact_log2(elem_size);
|
||||
}
|
||||
|
||||
void LIR_Assembler::emit_op3(LIR_Op3* op) {
|
||||
void LIR_Assembler::arithmetic_idiv(LIR_Op3* op, bool is_irem) {
|
||||
Register Rdividend = op->in_opr1()->as_register();
|
||||
Register Rdivisor = op->in_opr2()->as_register();
|
||||
Register Rscratch = op->in_opr3()->as_register();
|
||||
@ -1076,12 +1076,31 @@ void LIR_Assembler::emit_op3(LIR_Op3* op) {
|
||||
// convert division by a power of two into some shifts and logical operations
|
||||
}
|
||||
|
||||
if (op->code() == lir_irem) {
|
||||
__ corrected_idivl(Rresult, Rdividend, Rdivisor, true, rscratch1);
|
||||
} else if (op->code() == lir_idiv) {
|
||||
__ corrected_idivl(Rresult, Rdividend, Rdivisor, false, rscratch1);
|
||||
} else
|
||||
ShouldNotReachHere();
|
||||
__ corrected_idivl(Rresult, Rdividend, Rdivisor, is_irem, rscratch1);
|
||||
}
|
||||
|
||||
void LIR_Assembler::emit_op3(LIR_Op3* op) {
|
||||
switch (op->code()) {
|
||||
case lir_idiv:
|
||||
arithmetic_idiv(op, false);
|
||||
break;
|
||||
case lir_irem:
|
||||
arithmetic_idiv(op, true);
|
||||
break;
|
||||
case lir_fmad:
|
||||
__ fmaddd(op->result_opr()->as_double_reg(),
|
||||
op->in_opr1()->as_double_reg(),
|
||||
op->in_opr2()->as_double_reg(),
|
||||
op->in_opr3()->as_double_reg());
|
||||
break;
|
||||
case lir_fmaf:
|
||||
__ fmadds(op->result_opr()->as_float_reg(),
|
||||
op->in_opr1()->as_float_reg(),
|
||||
op->in_opr2()->as_float_reg(),
|
||||
op->in_opr3()->as_float_reg());
|
||||
break;
|
||||
default: ShouldNotReachHere(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) {
|
||||
@ -2001,7 +2020,7 @@ void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) {
|
||||
|
||||
void LIR_Assembler::emit_static_call_stub() {
|
||||
address call_pc = __ pc();
|
||||
address stub = __ start_a_stub(call_stub_size);
|
||||
address stub = __ start_a_stub(call_stub_size());
|
||||
if (stub == NULL) {
|
||||
bailout("static call stub overflow");
|
||||
return;
|
||||
@ -2014,7 +2033,7 @@ void LIR_Assembler::emit_static_call_stub() {
|
||||
__ movptr(rscratch1, 0);
|
||||
__ br(rscratch1);
|
||||
|
||||
assert(__ offset() - start <= call_stub_size, "stub too big");
|
||||
assert(__ offset() - start <= call_stub_size(), "stub too big");
|
||||
__ end_a_stub();
|
||||
}
|
||||
|
||||
|
||||
@ -68,14 +68,19 @@ friend class ArrayCopyStub;
|
||||
|
||||
void deoptimize_trap(CodeEmitInfo *info);
|
||||
|
||||
enum {
|
||||
_call_stub_size = 12 * NativeInstruction::instruction_size,
|
||||
_call_aot_stub_size = 0,
|
||||
_exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
|
||||
_deopt_handler_size = 7 * NativeInstruction::instruction_size
|
||||
};
|
||||
|
||||
void arithmetic_idiv(LIR_Op3* op, bool is_irem);
|
||||
|
||||
public:
|
||||
|
||||
void store_parameter(Register r, int offset_from_esp_in_words);
|
||||
void store_parameter(jint c, int offset_from_esp_in_words);
|
||||
void store_parameter(jobject c, int offset_from_esp_in_words);
|
||||
|
||||
enum { call_stub_size = 12 * NativeInstruction::instruction_size,
|
||||
exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
|
||||
deopt_handler_size = 7 * NativeInstruction::instruction_size };
|
||||
|
||||
#endif // CPU_AARCH64_VM_C1_LIRASSEMBLER_AARCH64_HPP
|
||||
|
||||
@ -1034,7 +1034,26 @@ void LIRGenerator::do_update_CRC32C(Intrinsic* x) {
|
||||
}
|
||||
|
||||
void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
|
||||
fatal("FMA intrinsic is not implemented on this platform");
|
||||
assert(x->number_of_arguments() == 3, "wrong type");
|
||||
assert(UseFMA, "Needs FMA instructions support.");
|
||||
LIRItem value(x->argument_at(0), this);
|
||||
LIRItem value1(x->argument_at(1), this);
|
||||
LIRItem value2(x->argument_at(2), this);
|
||||
|
||||
value.load_item();
|
||||
value1.load_item();
|
||||
value2.load_item();
|
||||
|
||||
LIR_Opr calc_input = value.result();
|
||||
LIR_Opr calc_input1 = value1.result();
|
||||
LIR_Opr calc_input2 = value2.result();
|
||||
LIR_Opr calc_result = rlock_result(x);
|
||||
|
||||
switch (x->id()) {
|
||||
case vmIntrinsics::_fmaD: __ fmad(calc_input, calc_input1, calc_input2, calc_result); break;
|
||||
case vmIntrinsics::_fmaF: __ fmaf(calc_input, calc_input1, calc_input2, calc_result); break;
|
||||
default: ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) {
|
||||
|
||||
@ -195,95 +195,22 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register
|
||||
}
|
||||
}
|
||||
|
||||
// Zero words; len is in bytes
|
||||
// Destroys all registers except addr
|
||||
// len must be a nonzero multiple of wordSize
|
||||
void C1_MacroAssembler::zero_memory(Register addr, Register len, Register t1) {
|
||||
assert_different_registers(addr, len, t1, rscratch1, rscratch2);
|
||||
|
||||
#ifdef ASSERT
|
||||
{ Label L;
|
||||
tst(len, BytesPerWord - 1);
|
||||
br(Assembler::EQ, L);
|
||||
stop("len is not a multiple of BytesPerWord");
|
||||
bind(L);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
block_comment("zero memory");
|
||||
#endif
|
||||
|
||||
Label loop;
|
||||
Label entry;
|
||||
|
||||
// Algorithm:
|
||||
//
|
||||
// scratch1 = cnt & 7;
|
||||
// cnt -= scratch1;
|
||||
// p += scratch1;
|
||||
// switch (scratch1) {
|
||||
// do {
|
||||
// cnt -= 8;
|
||||
// p[-8] = 0;
|
||||
// case 7:
|
||||
// p[-7] = 0;
|
||||
// case 6:
|
||||
// p[-6] = 0;
|
||||
// // ...
|
||||
// case 1:
|
||||
// p[-1] = 0;
|
||||
// case 0:
|
||||
// p += 8;
|
||||
// } while (cnt);
|
||||
// }
|
||||
|
||||
const int unroll = 8; // Number of str(zr) instructions we'll unroll
|
||||
|
||||
lsr(len, len, LogBytesPerWord);
|
||||
andr(rscratch1, len, unroll - 1); // tmp1 = cnt % unroll
|
||||
sub(len, len, rscratch1); // cnt -= unroll
|
||||
// t1 always points to the end of the region we're about to zero
|
||||
add(t1, addr, rscratch1, Assembler::LSL, LogBytesPerWord);
|
||||
adr(rscratch2, entry);
|
||||
sub(rscratch2, rscratch2, rscratch1, Assembler::LSL, 2);
|
||||
br(rscratch2);
|
||||
bind(loop);
|
||||
sub(len, len, unroll);
|
||||
for (int i = -unroll; i < 0; i++)
|
||||
str(zr, Address(t1, i * wordSize));
|
||||
bind(entry);
|
||||
add(t1, t1, unroll * wordSize);
|
||||
cbnz(len, loop);
|
||||
}
|
||||
|
||||
// preserves obj, destroys len_in_bytes
|
||||
void C1_MacroAssembler::initialize_body(Register obj, Register len_in_bytes, int hdr_size_in_bytes, Register t1) {
|
||||
assert(hdr_size_in_bytes >= 0, "header size must be positive or 0");
|
||||
Label done;
|
||||
assert(obj != len_in_bytes && obj != t1 && t1 != len_in_bytes, "registers must be different");
|
||||
assert((hdr_size_in_bytes & (BytesPerWord - 1)) == 0, "header size is not a multiple of BytesPerWord");
|
||||
Register index = len_in_bytes;
|
||||
// index is positive and ptr sized
|
||||
subs(index, index, hdr_size_in_bytes);
|
||||
|
||||
// len_in_bytes is positive and ptr sized
|
||||
subs(len_in_bytes, len_in_bytes, hdr_size_in_bytes);
|
||||
br(Assembler::EQ, done);
|
||||
// note: for the remaining code to work, index must be a multiple of BytesPerWord
|
||||
#ifdef ASSERT
|
||||
{ Label L;
|
||||
tst(index, BytesPerWord - 1);
|
||||
br(Assembler::EQ, L);
|
||||
stop("index is not a multiple of BytesPerWord");
|
||||
bind(L);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Preserve obj
|
||||
if (hdr_size_in_bytes)
|
||||
add(obj, obj, hdr_size_in_bytes);
|
||||
zero_memory(obj, index, t1);
|
||||
zero_memory(obj, len_in_bytes, t1);
|
||||
if (hdr_size_in_bytes)
|
||||
sub(obj, obj, hdr_size_in_bytes);
|
||||
|
||||
// done
|
||||
bind(done);
|
||||
}
|
||||
|
||||
@ -294,57 +221,59 @@ void C1_MacroAssembler::allocate_object(Register obj, Register t1, Register t2,
|
||||
|
||||
try_allocate(obj, noreg, object_size * BytesPerWord, t1, t2, slow_case);
|
||||
|
||||
initialize_object(obj, klass, noreg, object_size * HeapWordSize, t1, t2);
|
||||
initialize_object(obj, klass, noreg, object_size * HeapWordSize, t1, t2, UseTLAB);
|
||||
}
|
||||
|
||||
void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2) {
|
||||
void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2, bool is_tlab_allocated) {
|
||||
assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0,
|
||||
"con_size_in_bytes is not multiple of alignment");
|
||||
const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize;
|
||||
|
||||
initialize_header(obj, klass, noreg, t1, t2);
|
||||
|
||||
// clear rest of allocated space
|
||||
const Register index = t2;
|
||||
const int threshold = 16 * BytesPerWord; // approximate break even point for code size (see comments below)
|
||||
if (var_size_in_bytes != noreg) {
|
||||
mov(index, var_size_in_bytes);
|
||||
initialize_body(obj, index, hdr_size_in_bytes, t1);
|
||||
} else if (con_size_in_bytes <= threshold) {
|
||||
// use explicit null stores
|
||||
int i = hdr_size_in_bytes;
|
||||
if (i < con_size_in_bytes && (con_size_in_bytes % (2 * BytesPerWord))) {
|
||||
str(zr, Address(obj, i));
|
||||
i += BytesPerWord;
|
||||
}
|
||||
for (; i < con_size_in_bytes; i += 2 * BytesPerWord)
|
||||
stp(zr, zr, Address(obj, i));
|
||||
} else if (con_size_in_bytes > hdr_size_in_bytes) {
|
||||
block_comment("zero memory");
|
||||
// use loop to null out the fields
|
||||
if (!(UseTLAB && ZeroTLAB && is_tlab_allocated)) {
|
||||
// clear rest of allocated space
|
||||
const Register index = t2;
|
||||
const int threshold = 16 * BytesPerWord; // approximate break even point for code size (see comments below)
|
||||
if (var_size_in_bytes != noreg) {
|
||||
mov(index, var_size_in_bytes);
|
||||
initialize_body(obj, index, hdr_size_in_bytes, t1);
|
||||
} else if (con_size_in_bytes <= threshold) {
|
||||
// use explicit null stores
|
||||
int i = hdr_size_in_bytes;
|
||||
if (i < con_size_in_bytes && (con_size_in_bytes % (2 * BytesPerWord))) {
|
||||
str(zr, Address(obj, i));
|
||||
i += BytesPerWord;
|
||||
}
|
||||
for (; i < con_size_in_bytes; i += 2 * BytesPerWord)
|
||||
stp(zr, zr, Address(obj, i));
|
||||
} else if (con_size_in_bytes > hdr_size_in_bytes) {
|
||||
block_comment("zero memory");
|
||||
// use loop to null out the fields
|
||||
|
||||
int words = (con_size_in_bytes - hdr_size_in_bytes) / BytesPerWord;
|
||||
mov(index, words / 8);
|
||||
int words = (con_size_in_bytes - hdr_size_in_bytes) / BytesPerWord;
|
||||
mov(index, words / 8);
|
||||
|
||||
const int unroll = 8; // Number of str(zr) instructions we'll unroll
|
||||
int remainder = words % unroll;
|
||||
lea(rscratch1, Address(obj, hdr_size_in_bytes + remainder * BytesPerWord));
|
||||
const int unroll = 8; // Number of str(zr) instructions we'll unroll
|
||||
int remainder = words % unroll;
|
||||
lea(rscratch1, Address(obj, hdr_size_in_bytes + remainder * BytesPerWord));
|
||||
|
||||
Label entry_point, loop;
|
||||
b(entry_point);
|
||||
Label entry_point, loop;
|
||||
b(entry_point);
|
||||
|
||||
bind(loop);
|
||||
sub(index, index, 1);
|
||||
for (int i = -unroll; i < 0; i++) {
|
||||
if (-i == remainder)
|
||||
bind(entry_point);
|
||||
str(zr, Address(rscratch1, i * wordSize));
|
||||
}
|
||||
if (remainder == 0)
|
||||
bind(entry_point);
|
||||
add(rscratch1, rscratch1, unroll * wordSize);
|
||||
cbnz(index, loop);
|
||||
bind(loop);
|
||||
sub(index, index, 1);
|
||||
for (int i = -unroll; i < 0; i++) {
|
||||
if (-i == remainder)
|
||||
bind(entry_point);
|
||||
str(zr, Address(rscratch1, i * wordSize));
|
||||
}
|
||||
if (remainder == 0)
|
||||
bind(entry_point);
|
||||
add(rscratch1, rscratch1, unroll * wordSize);
|
||||
cbnz(index, loop);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
membar(StoreStore);
|
||||
|
||||
@ -36,7 +36,6 @@ using MacroAssembler::null_check;
|
||||
// initialization
|
||||
void pd_init() { _rsp_offset = 0; }
|
||||
|
||||
void zero_memory(Register addr, Register len, Register t1);
|
||||
|
||||
public:
|
||||
void try_allocate(
|
||||
@ -75,7 +74,8 @@ void zero_memory(Register addr, Register len, Register t1);
|
||||
Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
|
||||
int con_size_in_bytes, // object size in bytes if known at compile time
|
||||
Register t1, // temp register
|
||||
Register t2 // temp register
|
||||
Register t2, // temp register
|
||||
bool is_tlab_allocated // the object was allocated in a TLAB; relevant for the implementation of ZeroTLAB
|
||||
);
|
||||
|
||||
// allocation of fixed-size objects
|
||||
|
||||
@ -728,7 +728,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
|
||||
__ tlab_allocate(obj, obj_size, 0, t1, t2, slow_path);
|
||||
|
||||
__ initialize_object(obj, klass, obj_size, 0, t1, t2);
|
||||
__ initialize_object(obj, klass, obj_size, 0, t1, t2, /* is_tlab_allocated */ true);
|
||||
__ verify_oop(obj);
|
||||
__ ldp(r5, r19, Address(__ post(sp, 2 * wordSize)));
|
||||
__ ret(lr);
|
||||
@ -740,7 +740,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
__ eden_allocate(obj, obj_size, 0, t1, slow_path);
|
||||
__ incr_allocated_bytes(rthread, obj_size, 0, rscratch1);
|
||||
|
||||
__ initialize_object(obj, klass, obj_size, 0, t1, t2);
|
||||
__ initialize_object(obj, klass, obj_size, 0, t1, t2, /* is_tlab_allocated */ false);
|
||||
__ verify_oop(obj);
|
||||
__ ldp(r5, r19, Address(__ post(sp, 2 * wordSize)));
|
||||
__ ret(lr);
|
||||
@ -853,7 +853,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
__ andr(t1, t1, Klass::_lh_header_size_mask);
|
||||
__ sub(arr_size, arr_size, t1); // body length
|
||||
__ add(t1, t1, obj); // body start
|
||||
__ initialize_body(t1, arr_size, 0, t2);
|
||||
if (!ZeroTLAB) {
|
||||
__ initialize_body(t1, arr_size, 0, t2);
|
||||
}
|
||||
__ verify_oop(obj);
|
||||
|
||||
__ ret(lr);
|
||||
|
||||
@ -76,13 +76,13 @@ int CompiledStaticCall::reloc_to_interp_stub() {
|
||||
return 4; // 3 in emit_to_interp_stub + 1 in emit_call
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
|
||||
address stub = find_stub();
|
||||
void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
|
||||
address stub = find_stub(false /* is_aot */);
|
||||
guarantee(stub != NULL, "stub not found");
|
||||
|
||||
if (TraceICs) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
|
||||
tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
|
||||
p2i(instruction_address()),
|
||||
callee->name_and_sig_as_C_string());
|
||||
}
|
||||
@ -107,7 +107,7 @@ void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry)
|
||||
set_destination_mt_safe(stub);
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
|
||||
// Reset stub.
|
||||
address stub = static_stub->addr();
|
||||
@ -121,15 +121,15 @@ void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub)
|
||||
// Non-product mode code
|
||||
#ifndef PRODUCT
|
||||
|
||||
void CompiledStaticCall::verify() {
|
||||
void CompiledDirectStaticCall::verify() {
|
||||
// Verify call.
|
||||
NativeCall::verify();
|
||||
_call->verify();
|
||||
if (os::is_MP()) {
|
||||
verify_alignment();
|
||||
_call->verify_alignment();
|
||||
}
|
||||
|
||||
// Verify stub.
|
||||
address stub = find_stub();
|
||||
address stub = find_stub(false /* is_aot */);
|
||||
assert(stub != NULL, "no stub found for static call");
|
||||
// Creation also verifies the object.
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
|
||||
|
||||
@ -3944,12 +3944,82 @@ Register MacroAssembler::tlab_refill(Label& retry,
|
||||
add(top, top, t1);
|
||||
sub(top, top, (int32_t)ThreadLocalAllocBuffer::alignment_reserve_in_bytes());
|
||||
str(top, Address(rthread, in_bytes(JavaThread::tlab_end_offset())));
|
||||
|
||||
if (ZeroTLAB) {
|
||||
// This is a fast TLAB refill, therefore the GC is not notified of it.
|
||||
// So compiled code must fill the new TLAB with zeroes.
|
||||
ldr(top, Address(rthread, in_bytes(JavaThread::tlab_start_offset())));
|
||||
zero_memory(top,t1,t2);
|
||||
}
|
||||
|
||||
verify_tlab();
|
||||
b(retry);
|
||||
|
||||
return rthread; // for use by caller
|
||||
}
|
||||
|
||||
// Zero words; len is in bytes
|
||||
// Destroys all registers except addr
|
||||
// len must be a nonzero multiple of wordSize
|
||||
void MacroAssembler::zero_memory(Register addr, Register len, Register t1) {
|
||||
assert_different_registers(addr, len, t1, rscratch1, rscratch2);
|
||||
|
||||
#ifdef ASSERT
|
||||
{ Label L;
|
||||
tst(len, BytesPerWord - 1);
|
||||
br(Assembler::EQ, L);
|
||||
stop("len is not a multiple of BytesPerWord");
|
||||
bind(L);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
block_comment("zero memory");
|
||||
#endif
|
||||
|
||||
Label loop;
|
||||
Label entry;
|
||||
|
||||
// Algorithm:
|
||||
//
|
||||
// scratch1 = cnt & 7;
|
||||
// cnt -= scratch1;
|
||||
// p += scratch1;
|
||||
// switch (scratch1) {
|
||||
// do {
|
||||
// cnt -= 8;
|
||||
// p[-8] = 0;
|
||||
// case 7:
|
||||
// p[-7] = 0;
|
||||
// case 6:
|
||||
// p[-6] = 0;
|
||||
// // ...
|
||||
// case 1:
|
||||
// p[-1] = 0;
|
||||
// case 0:
|
||||
// p += 8;
|
||||
// } while (cnt);
|
||||
// }
|
||||
|
||||
const int unroll = 8; // Number of str(zr) instructions we'll unroll
|
||||
|
||||
lsr(len, len, LogBytesPerWord);
|
||||
andr(rscratch1, len, unroll - 1); // tmp1 = cnt % unroll
|
||||
sub(len, len, rscratch1); // cnt -= unroll
|
||||
// t1 always points to the end of the region we're about to zero
|
||||
add(t1, addr, rscratch1, Assembler::LSL, LogBytesPerWord);
|
||||
adr(rscratch2, entry);
|
||||
sub(rscratch2, rscratch2, rscratch1, Assembler::LSL, 2);
|
||||
br(rscratch2);
|
||||
bind(loop);
|
||||
sub(len, len, unroll);
|
||||
for (int i = -unroll; i < 0; i++)
|
||||
str(zr, Address(t1, i * wordSize));
|
||||
bind(entry);
|
||||
add(t1, t1, unroll * wordSize);
|
||||
cbnz(len, loop);
|
||||
}
|
||||
|
||||
// Defines obj, preserves var_size_in_bytes
|
||||
void MacroAssembler::eden_allocate(Register obj,
|
||||
Register var_size_in_bytes,
|
||||
|
||||
@ -857,6 +857,7 @@ public:
|
||||
Label& slow_case // continuation point if fast allocation fails
|
||||
);
|
||||
Register tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case); // returns TLS address
|
||||
void zero_memory(Register addr, Register len, Register t1);
|
||||
void verify_tlab();
|
||||
|
||||
void incr_allocated_bytes(Register thread,
|
||||
|
||||
@ -204,8 +204,25 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
|
||||
generate_transcendental_entry(kind, 2);
|
||||
break;
|
||||
case Interpreter::java_lang_math_fmaD :
|
||||
if (UseFMA) {
|
||||
entry_point = __ pc();
|
||||
__ ldrd(v0, Address(esp, 4 * Interpreter::stackElementSize));
|
||||
__ ldrd(v1, Address(esp, 2 * Interpreter::stackElementSize));
|
||||
__ ldrd(v2, Address(esp));
|
||||
__ fmaddd(v0, v0, v1, v2);
|
||||
__ mov(sp, r13); // Restore caller's SP
|
||||
}
|
||||
break;
|
||||
case Interpreter::java_lang_math_fmaF :
|
||||
return NULL;
|
||||
if (UseFMA) {
|
||||
entry_point = __ pc();
|
||||
__ ldrs(v0, Address(esp, 2 * Interpreter::stackElementSize));
|
||||
__ ldrs(v1, Address(esp, Interpreter::stackElementSize));
|
||||
__ ldrs(v2, Address(esp));
|
||||
__ fmadds(v0, v0, v1, v2);
|
||||
__ mov(sp, r13); // Restore caller's SP
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
@ -262,9 +262,8 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
|
||||
}
|
||||
|
||||
if (UseFMA) {
|
||||
warning("FMA instructions are not available on this CPU");
|
||||
FLAG_SET_DEFAULT(UseFMA, false);
|
||||
if (FLAG_IS_DEFAULT(UseFMA)) {
|
||||
FLAG_SET_DEFAULT(UseFMA, true);
|
||||
}
|
||||
|
||||
if (auxv & (HWCAP_SHA1 | HWCAP_SHA2)) {
|
||||
|
||||
@ -153,7 +153,7 @@ int LIR_Assembler::emit_exception_handler() {
|
||||
__ nop();
|
||||
|
||||
// Generate code for the exception handler.
|
||||
address handler_base = __ start_a_stub(exception_handler_size);
|
||||
address handler_base = __ start_a_stub(exception_handler_size());
|
||||
|
||||
if (handler_base == NULL) {
|
||||
// Not enough space left for the handler.
|
||||
@ -168,7 +168,7 @@ int LIR_Assembler::emit_exception_handler() {
|
||||
__ mtctr(R0);
|
||||
__ bctr();
|
||||
|
||||
guarantee(code_offset() - offset <= exception_handler_size, "overflow");
|
||||
guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
|
||||
__ end_a_stub();
|
||||
|
||||
return offset;
|
||||
@ -233,7 +233,7 @@ int LIR_Assembler::emit_deopt_handler() {
|
||||
__ nop();
|
||||
|
||||
// Generate code for deopt handler.
|
||||
address handler_base = __ start_a_stub(deopt_handler_size);
|
||||
address handler_base = __ start_a_stub(deopt_handler_size());
|
||||
|
||||
if (handler_base == NULL) {
|
||||
// Not enough space left for the handler.
|
||||
@ -244,7 +244,7 @@ int LIR_Assembler::emit_deopt_handler() {
|
||||
int offset = code_offset();
|
||||
__ bl64_patchable(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type);
|
||||
|
||||
guarantee(code_offset() - offset <= deopt_handler_size, "overflow");
|
||||
guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
|
||||
__ end_a_stub();
|
||||
|
||||
return offset;
|
||||
@ -1307,7 +1307,7 @@ int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) {
|
||||
|
||||
void LIR_Assembler::emit_static_call_stub() {
|
||||
address call_pc = __ pc();
|
||||
address stub = __ start_a_stub(max_static_call_stub_size);
|
||||
address stub = __ start_a_stub(static_call_stub_size());
|
||||
if (stub == NULL) {
|
||||
bailout("static call stub overflow");
|
||||
return;
|
||||
@ -1346,7 +1346,7 @@ void LIR_Assembler::emit_static_call_stub() {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(__ offset() - start <= max_static_call_stub_size, "stub too big");
|
||||
assert(__ offset() - start <= static_call_stub_size(), "stub too big");
|
||||
__ end_a_stub();
|
||||
}
|
||||
|
||||
|
||||
@ -60,10 +60,21 @@
|
||||
bool emit_trampoline_stub_for_call(address target, Register Rtoc = noreg);
|
||||
|
||||
enum {
|
||||
max_static_call_stub_size = 4 * BytesPerInstWord + MacroAssembler::b64_patchable_size,
|
||||
call_stub_size = max_static_call_stub_size + MacroAssembler::trampoline_stub_size, // or smaller
|
||||
exception_handler_size = MacroAssembler::b64_patchable_size, // or smaller
|
||||
deopt_handler_size = MacroAssembler::bl64_patchable_size
|
||||
_static_call_stub_size = 4 * BytesPerInstWord + MacroAssembler::b64_patchable_size, // or smaller
|
||||
_call_stub_size = _static_call_stub_size + MacroAssembler::trampoline_stub_size, // or smaller
|
||||
_call_aot_stub_size = 0,
|
||||
_exception_handler_size = MacroAssembler::b64_patchable_size, // or smaller
|
||||
_deopt_handler_size = MacroAssembler::bl64_patchable_size
|
||||
};
|
||||
|
||||
// '_static_call_stub_size' is only used on ppc (see LIR_Assembler::emit_static_call_stub()
|
||||
// in c1_LIRAssembler_ppc.cpp. The other, shared getters are defined in c1_LIRAssembler.hpp
|
||||
static int static_call_stub_size() {
|
||||
if (UseAOT) {
|
||||
return _static_call_stub_size + _call_aot_stub_size;
|
||||
} else {
|
||||
return _static_call_stub_size;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CPU_PPC_VM_C1_LIRASSEMBLER_PPC_HPP
|
||||
|
||||
@ -238,72 +238,15 @@ void C1_MacroAssembler::initialize_body(Register obj, Register tmp1, Register tm
|
||||
int obj_size_in_bytes, int hdr_size_in_bytes) {
|
||||
const int index = (obj_size_in_bytes - hdr_size_in_bytes) / HeapWordSize;
|
||||
|
||||
const int cl_size = VM_Version::L1_data_cache_line_size(),
|
||||
cl_dwords = cl_size>>3,
|
||||
cl_dw_addr_bits = exact_log2(cl_dwords);
|
||||
|
||||
const Register tmp = R0,
|
||||
base_ptr = tmp1,
|
||||
cnt_dwords = tmp2;
|
||||
|
||||
if (index <= 6) {
|
||||
// Use explicit NULL stores.
|
||||
if (index > 0) { li(tmp, 0); }
|
||||
for (int i = 0; i < index; ++i) { std(tmp, hdr_size_in_bytes + i * HeapWordSize, obj); }
|
||||
|
||||
} else if (index < (2<<cl_dw_addr_bits)-1) {
|
||||
// simple loop
|
||||
Label loop;
|
||||
|
||||
li(cnt_dwords, index);
|
||||
addi(base_ptr, obj, hdr_size_in_bytes); // Compute address of first element.
|
||||
li(tmp, 0);
|
||||
mtctr(cnt_dwords); // Load counter.
|
||||
bind(loop);
|
||||
std(tmp, 0, base_ptr); // Clear 8byte aligned block.
|
||||
addi(base_ptr, base_ptr, 8);
|
||||
bdnz(loop);
|
||||
|
||||
// 2x unrolled loop is shorter with more than 9 HeapWords.
|
||||
if (index <= 9) {
|
||||
clear_memory_unrolled(obj, index, R0, hdr_size_in_bytes);
|
||||
} else {
|
||||
// like clear_memory_doubleword
|
||||
Label startloop, fast, fastloop, restloop, done;
|
||||
const Register base_ptr = tmp1,
|
||||
cnt_dwords = tmp2;
|
||||
|
||||
addi(base_ptr, obj, hdr_size_in_bytes); // Compute address of first element.
|
||||
load_const_optimized(cnt_dwords, index);
|
||||
rldicl_(tmp, base_ptr, 64-3, 64-cl_dw_addr_bits); // Extract dword offset within first cache line.
|
||||
beq(CCR0, fast); // Already 128byte aligned.
|
||||
|
||||
subfic(tmp, tmp, cl_dwords);
|
||||
mtctr(tmp); // Set ctr to hit 128byte boundary (0<ctr<cl_dwords).
|
||||
subf(cnt_dwords, tmp, cnt_dwords); // rest.
|
||||
li(tmp, 0);
|
||||
|
||||
bind(startloop); // Clear at the beginning to reach 128byte boundary.
|
||||
std(tmp, 0, base_ptr); // Clear 8byte aligned block.
|
||||
addi(base_ptr, base_ptr, 8);
|
||||
bdnz(startloop);
|
||||
|
||||
bind(fast); // Clear 128byte blocks.
|
||||
srdi(tmp, cnt_dwords, cl_dw_addr_bits); // Loop count for 128byte loop (>0).
|
||||
andi(cnt_dwords, cnt_dwords, cl_dwords-1); // Rest in dwords.
|
||||
mtctr(tmp); // Load counter.
|
||||
|
||||
bind(fastloop);
|
||||
dcbz(base_ptr); // Clear 128byte aligned block.
|
||||
addi(base_ptr, base_ptr, cl_size);
|
||||
bdnz(fastloop);
|
||||
|
||||
cmpdi(CCR0, cnt_dwords, 0); // size 0?
|
||||
beq(CCR0, done); // rest == 0
|
||||
li(tmp, 0);
|
||||
mtctr(cnt_dwords); // Load counter.
|
||||
|
||||
bind(restloop); // Clear rest.
|
||||
std(tmp, 0, base_ptr); // Clear 8byte aligned block.
|
||||
addi(base_ptr, base_ptr, 8);
|
||||
bdnz(restloop);
|
||||
|
||||
bind(done);
|
||||
addi(base_ptr, obj, hdr_size_in_bytes); // Compute address of first element.
|
||||
clear_memory_doubleword(base_ptr, cnt_dwords, R0, index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// A PPC CompiledStaticCall looks like this:
|
||||
// A PPC CompiledDirectStaticCall looks like this:
|
||||
//
|
||||
// >>>> consts
|
||||
//
|
||||
@ -163,13 +163,13 @@ int CompiledStaticCall::reloc_to_interp_stub() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
|
||||
address stub = find_stub();
|
||||
void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
|
||||
address stub = find_stub(/*is_aot*/ false);
|
||||
guarantee(stub != NULL, "stub not found");
|
||||
|
||||
if (TraceICs) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
|
||||
tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
|
||||
p2i(instruction_address()),
|
||||
callee->name_and_sig_as_C_string());
|
||||
}
|
||||
@ -196,7 +196,7 @@ void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry)
|
||||
set_destination_mt_safe(stub);
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
|
||||
// Reset stub.
|
||||
address stub = static_stub->addr();
|
||||
@ -212,15 +212,15 @@ void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub)
|
||||
// Non-product mode code
|
||||
#ifndef PRODUCT
|
||||
|
||||
void CompiledStaticCall::verify() {
|
||||
void CompiledDirectStaticCall::verify() {
|
||||
// Verify call.
|
||||
NativeCall::verify();
|
||||
_call->verify();
|
||||
if (os::is_MP()) {
|
||||
verify_alignment();
|
||||
_call->verify_alignment();
|
||||
}
|
||||
|
||||
// Verify stub.
|
||||
address stub = find_stub();
|
||||
address stub = find_stub(/*is_aot*/ false);
|
||||
assert(stub != NULL, "no stub found for static call");
|
||||
// Creation also verifies the object.
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + IC_pos_in_java_to_interp_stub);
|
||||
|
||||
@ -77,7 +77,8 @@ define_pd_global(uintx, TypeProfileLevel, 111);
|
||||
|
||||
define_pd_global(bool, CompactStrings, true);
|
||||
|
||||
define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong);
|
||||
// 2x unrolled loop is shorter with more than 9 HeapWords.
|
||||
define_pd_global(intx, InitArrayShortSize, 9*BytesPerLong);
|
||||
|
||||
// Platform dependent flag handling: flags only defined on this platform.
|
||||
#define ARCH_FLAGS(develop, \
|
||||
|
||||
@ -3332,53 +3332,90 @@ void MacroAssembler::load_mirror_from_const_method(Register mirror, Register con
|
||||
}
|
||||
|
||||
// Clear Array
|
||||
// For very short arrays. tmp == R0 is allowed.
|
||||
void MacroAssembler::clear_memory_unrolled(Register base_ptr, int cnt_dwords, Register tmp, int offset) {
|
||||
if (cnt_dwords > 0) { li(tmp, 0); }
|
||||
for (int i = 0; i < cnt_dwords; ++i) { std(tmp, offset + i * 8, base_ptr); }
|
||||
}
|
||||
|
||||
// Version for constant short array length. Kills base_ptr. tmp == R0 is allowed.
|
||||
void MacroAssembler::clear_memory_constlen(Register base_ptr, int cnt_dwords, Register tmp) {
|
||||
if (cnt_dwords < 8) {
|
||||
clear_memory_unrolled(base_ptr, cnt_dwords, tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
Label loop;
|
||||
const long loopcnt = cnt_dwords >> 1,
|
||||
remainder = cnt_dwords & 1;
|
||||
|
||||
li(tmp, loopcnt);
|
||||
mtctr(tmp);
|
||||
li(tmp, 0);
|
||||
bind(loop);
|
||||
std(tmp, 0, base_ptr);
|
||||
std(tmp, 8, base_ptr);
|
||||
addi(base_ptr, base_ptr, 16);
|
||||
bdnz(loop);
|
||||
if (remainder) { std(tmp, 0, base_ptr); }
|
||||
}
|
||||
|
||||
// Kills both input registers. tmp == R0 is allowed.
|
||||
void MacroAssembler::clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp) {
|
||||
void MacroAssembler::clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp, long const_cnt) {
|
||||
// Procedure for large arrays (uses data cache block zero instruction).
|
||||
Label startloop, fast, fastloop, small_rest, restloop, done;
|
||||
const int cl_size = VM_Version::L1_data_cache_line_size(),
|
||||
cl_dwords = cl_size>>3,
|
||||
cl_dwords = cl_size >> 3,
|
||||
cl_dw_addr_bits = exact_log2(cl_dwords),
|
||||
dcbz_min = 1; // Min count of dcbz executions, needs to be >0.
|
||||
dcbz_min = 1, // Min count of dcbz executions, needs to be >0.
|
||||
min_cnt = ((dcbz_min + 1) << cl_dw_addr_bits) - 1;
|
||||
|
||||
//2:
|
||||
cmpdi(CCR1, cnt_dwords, ((dcbz_min+1)<<cl_dw_addr_bits)-1); // Big enough? (ensure >=dcbz_min lines included).
|
||||
blt(CCR1, small_rest); // Too small.
|
||||
rldicl_(tmp, base_ptr, 64-3, 64-cl_dw_addr_bits); // Extract dword offset within first cache line.
|
||||
beq(CCR0, fast); // Already 128byte aligned.
|
||||
if (const_cnt >= 0) {
|
||||
// Constant case.
|
||||
if (const_cnt < min_cnt) {
|
||||
clear_memory_constlen(base_ptr, const_cnt, tmp);
|
||||
return;
|
||||
}
|
||||
load_const_optimized(cnt_dwords, const_cnt, tmp);
|
||||
} else {
|
||||
// cnt_dwords already loaded in register. Need to check size.
|
||||
cmpdi(CCR1, cnt_dwords, min_cnt); // Big enough? (ensure >= dcbz_min lines included).
|
||||
blt(CCR1, small_rest);
|
||||
}
|
||||
rldicl_(tmp, base_ptr, 64-3, 64-cl_dw_addr_bits); // Extract dword offset within first cache line.
|
||||
beq(CCR0, fast); // Already 128byte aligned.
|
||||
|
||||
subfic(tmp, tmp, cl_dwords);
|
||||
mtctr(tmp); // Set ctr to hit 128byte boundary (0<ctr<cl_dwords).
|
||||
subf(cnt_dwords, tmp, cnt_dwords); // rest.
|
||||
li(tmp, 0);
|
||||
//10:
|
||||
|
||||
bind(startloop); // Clear at the beginning to reach 128byte boundary.
|
||||
std(tmp, 0, base_ptr); // Clear 8byte aligned block.
|
||||
addi(base_ptr, base_ptr, 8);
|
||||
bdnz(startloop);
|
||||
//13:
|
||||
|
||||
bind(fast); // Clear 128byte blocks.
|
||||
srdi(tmp, cnt_dwords, cl_dw_addr_bits); // Loop count for 128byte loop (>0).
|
||||
andi(cnt_dwords, cnt_dwords, cl_dwords-1); // Rest in dwords.
|
||||
mtctr(tmp); // Load counter.
|
||||
//16:
|
||||
|
||||
bind(fastloop);
|
||||
dcbz(base_ptr); // Clear 128byte aligned block.
|
||||
addi(base_ptr, base_ptr, cl_size);
|
||||
bdnz(fastloop);
|
||||
if (InsertEndGroupPPC64) { endgroup(); } else { nop(); }
|
||||
//20:
|
||||
|
||||
bind(small_rest);
|
||||
cmpdi(CCR0, cnt_dwords, 0); // size 0?
|
||||
beq(CCR0, done); // rest == 0
|
||||
li(tmp, 0);
|
||||
mtctr(cnt_dwords); // Load counter.
|
||||
//24:
|
||||
|
||||
bind(restloop); // Clear rest.
|
||||
std(tmp, 0, base_ptr); // Clear 8byte aligned block.
|
||||
addi(base_ptr, base_ptr, 8);
|
||||
bdnz(restloop);
|
||||
//27:
|
||||
|
||||
bind(done);
|
||||
}
|
||||
|
||||
|
||||
@ -755,7 +755,9 @@ class MacroAssembler: public Assembler {
|
||||
is_trap_range_check_g(x) || is_trap_range_check_ge(x);
|
||||
}
|
||||
|
||||
void clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp = R0);
|
||||
void clear_memory_unrolled(Register base_ptr, int cnt_dwords, Register tmp = R0, int offset = 0);
|
||||
void clear_memory_constlen(Register base_ptr, int cnt_dwords, Register tmp = R0);
|
||||
void clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp = R0, long const_cnt = -1);
|
||||
|
||||
#ifdef COMPILER2
|
||||
// Intrinsics for CompactStrings
|
||||
|
||||
@ -965,10 +965,7 @@ static int cc_to_biint(int cc, int flags_reg) {
|
||||
// is the number of bytes (not instructions) which will be inserted before
|
||||
// the instruction. The padding must match the size of a NOP instruction.
|
||||
|
||||
int inlineCallClearArrayNode::compute_padding(int current_offset) const {
|
||||
int desired_padding = (2*4-current_offset)&31; // see MacroAssembler::clear_memory_doubleword
|
||||
return (desired_padding <= 3*4) ? desired_padding : 0;
|
||||
}
|
||||
// Currently not used on this platform.
|
||||
|
||||
//=============================================================================
|
||||
|
||||
@ -4066,6 +4063,14 @@ operand immL() %{
|
||||
interface(CONST_INTER);
|
||||
%}
|
||||
|
||||
operand immLmax30() %{
|
||||
predicate((n->get_long() <= 30));
|
||||
match(ConL);
|
||||
op_cost(0);
|
||||
format %{ %}
|
||||
interface(CONST_INTER);
|
||||
%}
|
||||
|
||||
// Long Immediate: 16-bit
|
||||
operand immL16() %{
|
||||
predicate(Assembler::is_simm(n->get_long(), 16));
|
||||
@ -11735,18 +11740,44 @@ instruct array_size(iRegLdst dst, iRegPsrc end, iRegPsrc start) %{
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// Clear-array with dynamic array-size.
|
||||
instruct inlineCallClearArray(rarg1RegL cnt, rarg2RegP base, Universe dummy, regCTR ctr) %{
|
||||
// Clear-array with constant short array length. The versions below can use dcbz with cnt > 30.
|
||||
instruct inlineCallClearArrayShort(immLmax30 cnt, rarg2RegP base, Universe dummy, regCTR ctr) %{
|
||||
match(Set dummy (ClearArray cnt base));
|
||||
effect(USE_KILL cnt, USE_KILL base, KILL ctr);
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
|
||||
ins_alignment(4); // 'compute_padding()' gets called, up to this number-1 nops will get inserted.
|
||||
effect(USE_KILL base, KILL ctr);
|
||||
ins_cost(2 * MEMORY_REF_COST);
|
||||
|
||||
format %{ "ClearArray $cnt, $base" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ clear_memory_doubleword($base$$Register, $cnt$$Register); // kills cnt, base, R0
|
||||
__ clear_memory_constlen($base$$Register, $cnt$$constant, R0); // kills base, R0
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// Clear-array with constant large array length.
|
||||
instruct inlineCallClearArrayLarge(immL cnt, rarg2RegP base, Universe dummy, iRegLdst tmp, regCTR ctr) %{
|
||||
match(Set dummy (ClearArray cnt base));
|
||||
effect(USE_KILL base, TEMP tmp, KILL ctr);
|
||||
ins_cost(3 * MEMORY_REF_COST);
|
||||
|
||||
format %{ "ClearArray $cnt, $base \t// KILL $tmp" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ clear_memory_doubleword($base$$Register, $tmp$$Register, R0, $cnt$$constant); // kills base, R0
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// Clear-array with dynamic array length.
|
||||
instruct inlineCallClearArray(rarg1RegL cnt, rarg2RegP base, Universe dummy, regCTR ctr) %{
|
||||
match(Set dummy (ClearArray cnt base));
|
||||
effect(USE_KILL cnt, USE_KILL base, KILL ctr);
|
||||
ins_cost(4 * MEMORY_REF_COST);
|
||||
|
||||
format %{ "ClearArray $cnt, $base" %}
|
||||
ins_encode %{
|
||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||
__ clear_memory_doubleword($base$$Register, $cnt$$Register, R0); // kills cnt, base, R0
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
@ -153,7 +153,7 @@ int LIR_Assembler::emit_exception_handler() {
|
||||
__ nop();
|
||||
|
||||
// Generate code for exception handler.
|
||||
address handler_base = __ start_a_stub(exception_handler_size);
|
||||
address handler_base = __ start_a_stub(exception_handler_size());
|
||||
if (handler_base == NULL) {
|
||||
// Not enough space left for the handler.
|
||||
bailout("exception handler overflow");
|
||||
@ -166,7 +166,7 @@ int LIR_Assembler::emit_exception_handler() {
|
||||
address call_addr = emit_call_c(a);
|
||||
CHECK_BAILOUT_(-1);
|
||||
__ should_not_reach_here();
|
||||
guarantee(code_offset() - offset <= exception_handler_size, "overflow");
|
||||
guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
|
||||
__ end_a_stub();
|
||||
|
||||
return offset;
|
||||
@ -251,7 +251,7 @@ int LIR_Assembler::emit_deopt_handler() {
|
||||
__ nop();
|
||||
|
||||
// Generate code for exception handler.
|
||||
address handler_base = __ start_a_stub(deopt_handler_size);
|
||||
address handler_base = __ start_a_stub(deopt_handler_size());
|
||||
if (handler_base == NULL) {
|
||||
// Not enough space left for the handler.
|
||||
bailout("deopt handler overflow");
|
||||
@ -260,7 +260,7 @@ int LIR_Assembler::emit_deopt_handler() {
|
||||
// Size must be constant (see HandlerImpl::emit_deopt_handler).
|
||||
__ load_const(Z_R1_scratch, SharedRuntime::deopt_blob()->unpack());
|
||||
__ call(Z_R1_scratch);
|
||||
guarantee(code_offset() - offset <= deopt_handler_size, "overflow");
|
||||
guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
|
||||
__ end_a_stub();
|
||||
|
||||
return offset;
|
||||
@ -1157,7 +1157,7 @@ void LIR_Assembler::emit_static_call_stub() {
|
||||
// compiled code to calling interpreted code.
|
||||
|
||||
address call_pc = __ pc();
|
||||
address stub = __ start_a_stub(call_stub_size);
|
||||
address stub = __ start_a_stub(call_stub_size());
|
||||
if (stub == NULL) {
|
||||
bailout("static call stub overflow");
|
||||
return;
|
||||
@ -1180,7 +1180,7 @@ void LIR_Assembler::emit_static_call_stub() {
|
||||
}
|
||||
|
||||
__ z_br(Z_R1);
|
||||
assert(__ offset() - start <= call_stub_size, "stub too big");
|
||||
assert(__ offset() - start <= call_stub_size(), "stub too big");
|
||||
__ end_a_stub(); // Update current stubs pointer and restore insts_end.
|
||||
}
|
||||
|
||||
|
||||
@ -46,9 +46,10 @@
|
||||
}
|
||||
|
||||
enum {
|
||||
call_stub_size = 512, // See Compile::MAX_stubs_size and CompiledStaticCall::emit_to_interp_stub.
|
||||
exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(128),
|
||||
deopt_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(64)
|
||||
_call_stub_size = 512, // See Compile::MAX_stubs_size and CompiledStaticCall::emit_to_interp_stub.
|
||||
_call_aot_stub_size = 0,
|
||||
_exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(128),
|
||||
_deopt_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(64)
|
||||
};
|
||||
|
||||
#endif // CPU_S390_VM_C1_LIRASSEMBLER_S390_HPP
|
||||
|
||||
@ -90,19 +90,19 @@ int CompiledStaticCall::reloc_to_interp_stub() {
|
||||
return 5; // 4 in emit_java_to_interp + 1 in Java_Static_Call
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
|
||||
address stub = find_stub();
|
||||
void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
|
||||
address stub = find_stub(/*is_aot*/ false);
|
||||
guarantee(stub != NULL, "stub not found");
|
||||
|
||||
if (TraceICs) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
|
||||
tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
|
||||
p2i(instruction_address()),
|
||||
callee->name_and_sig_as_C_string());
|
||||
}
|
||||
|
||||
// Creation also verifies the object.
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + get_IC_pos_in_java_to_interp_stub());
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeCall::get_IC_pos_in_java_to_interp_stub());
|
||||
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
|
||||
|
||||
// A generated lambda form might be deleted from the Lambdaform
|
||||
@ -123,13 +123,13 @@ void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry)
|
||||
set_destination_mt_safe(stub);
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
|
||||
// Reset stub.
|
||||
address stub = static_stub->addr();
|
||||
assert(stub != NULL, "stub not found");
|
||||
// Creation also verifies the object.
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + get_IC_pos_in_java_to_interp_stub());
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeCall::get_IC_pos_in_java_to_interp_stub());
|
||||
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
|
||||
method_holder->set_data(0);
|
||||
jump->set_jump_destination((address)-1);
|
||||
@ -139,18 +139,18 @@ void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub)
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
void CompiledStaticCall::verify() {
|
||||
void CompiledDirectStaticCall::verify() {
|
||||
// Verify call.
|
||||
NativeCall::verify();
|
||||
_call->verify();
|
||||
if (os::is_MP()) {
|
||||
verify_alignment();
|
||||
_call->verify_alignment();
|
||||
}
|
||||
|
||||
// Verify stub.
|
||||
address stub = find_stub();
|
||||
address stub = find_stub(/*is_aot*/ false);
|
||||
assert(stub != NULL, "no stub found for static call");
|
||||
// Creation also verifies the object.
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + get_IC_pos_in_java_to_interp_stub());
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeCall::get_IC_pos_in_java_to_interp_stub());
|
||||
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
|
||||
|
||||
// Verify state.
|
||||
|
||||
@ -287,7 +287,7 @@ int LIR_Assembler::emit_exception_handler() {
|
||||
// generate code for exception handler
|
||||
ciMethod* method = compilation()->method();
|
||||
|
||||
address handler_base = __ start_a_stub(exception_handler_size);
|
||||
address handler_base = __ start_a_stub(exception_handler_size());
|
||||
|
||||
if (handler_base == NULL) {
|
||||
// not enough space left for the handler
|
||||
@ -300,7 +300,7 @@ int LIR_Assembler::emit_exception_handler() {
|
||||
__ call(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id), relocInfo::runtime_call_type);
|
||||
__ delayed()->nop();
|
||||
__ should_not_reach_here();
|
||||
guarantee(code_offset() - offset <= exception_handler_size, "overflow");
|
||||
guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
|
||||
__ end_a_stub();
|
||||
|
||||
return offset;
|
||||
@ -375,7 +375,7 @@ int LIR_Assembler::emit_deopt_handler() {
|
||||
|
||||
// generate code for deopt handler
|
||||
ciMethod* method = compilation()->method();
|
||||
address handler_base = __ start_a_stub(deopt_handler_size);
|
||||
address handler_base = __ start_a_stub(deopt_handler_size());
|
||||
if (handler_base == NULL) {
|
||||
// not enough space left for the handler
|
||||
bailout("deopt handler overflow");
|
||||
@ -386,7 +386,7 @@ int LIR_Assembler::emit_deopt_handler() {
|
||||
AddressLiteral deopt_blob(SharedRuntime::deopt_blob()->unpack());
|
||||
__ JUMP(deopt_blob, G3_scratch, 0); // sethi;jmp
|
||||
__ delayed()->nop();
|
||||
guarantee(code_offset() - offset <= deopt_handler_size, "overflow");
|
||||
guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
|
||||
__ end_a_stub();
|
||||
|
||||
return offset;
|
||||
@ -1493,7 +1493,7 @@ int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) {
|
||||
|
||||
void LIR_Assembler::emit_static_call_stub() {
|
||||
address call_pc = __ pc();
|
||||
address stub = __ start_a_stub(call_stub_size);
|
||||
address stub = __ start_a_stub(call_stub_size());
|
||||
if (stub == NULL) {
|
||||
bailout("static call stub overflow");
|
||||
return;
|
||||
@ -1508,7 +1508,7 @@ void LIR_Assembler::emit_static_call_stub() {
|
||||
__ jump_to(addrlit, G3);
|
||||
__ delayed()->nop();
|
||||
|
||||
assert(__ offset() - start <= call_stub_size, "stub too big");
|
||||
assert(__ offset() - start <= call_stub_size(), "stub too big");
|
||||
__ end_a_stub();
|
||||
}
|
||||
|
||||
|
||||
@ -59,17 +59,20 @@
|
||||
// Setup pointers to MDO, MDO slot, also compute offset bias to access the slot.
|
||||
void setup_md_access(ciMethod* method, int bci,
|
||||
ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias);
|
||||
|
||||
enum {
|
||||
#ifdef _LP64
|
||||
_call_stub_size = 68,
|
||||
#else
|
||||
_call_stub_size = 20,
|
||||
#endif // _LP64
|
||||
_call_aot_stub_size = 0,
|
||||
_exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(128),
|
||||
_deopt_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(64)
|
||||
};
|
||||
|
||||
public:
|
||||
void pack64(LIR_Opr src, LIR_Opr dst);
|
||||
void unpack64(LIR_Opr src, LIR_Opr dst);
|
||||
|
||||
enum {
|
||||
#ifdef _LP64
|
||||
call_stub_size = 68,
|
||||
#else
|
||||
call_stub_size = 20,
|
||||
#endif // _LP64
|
||||
exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(128),
|
||||
deopt_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(64) };
|
||||
|
||||
#endif // CPU_SPARC_VM_C1_LIRASSEMBLER_SPARC_HPP
|
||||
|
||||
@ -85,13 +85,13 @@ int CompiledStaticCall::reloc_to_interp_stub() {
|
||||
return 10; // 4 in emit_java_to_interp + 1 in Java_Static_Call
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
|
||||
address stub = find_stub();
|
||||
void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
|
||||
address stub = find_stub(/*is_aot*/ false);
|
||||
guarantee(stub != NULL, "stub not found");
|
||||
|
||||
if (TraceICs) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
|
||||
tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
|
||||
p2i(instruction_address()),
|
||||
callee->name_and_sig_as_C_string());
|
||||
}
|
||||
@ -118,7 +118,7 @@ void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry)
|
||||
set_destination_mt_safe(stub);
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
|
||||
// Reset stub.
|
||||
address stub = static_stub->addr();
|
||||
@ -134,15 +134,15 @@ void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub)
|
||||
// Non-product mode code
|
||||
#ifndef PRODUCT
|
||||
|
||||
void CompiledStaticCall::verify() {
|
||||
void CompiledDirectStaticCall::verify() {
|
||||
// Verify call.
|
||||
NativeCall::verify();
|
||||
_call->verify();
|
||||
if (os::is_MP()) {
|
||||
verify_alignment();
|
||||
_call->verify_alignment();
|
||||
}
|
||||
|
||||
// Verify stub.
|
||||
address stub = find_stub();
|
||||
address stub = find_stub(/*is_aot*/ false);
|
||||
assert(stub != NULL, "no stub found for static call");
|
||||
// Creation also verifies the object.
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
|
||||
|
||||
@ -393,7 +393,7 @@ int LIR_Assembler::emit_exception_handler() {
|
||||
__ nop();
|
||||
|
||||
// generate code for exception handler
|
||||
address handler_base = __ start_a_stub(exception_handler_size);
|
||||
address handler_base = __ start_a_stub(exception_handler_size());
|
||||
if (handler_base == NULL) {
|
||||
// not enough space left for the handler
|
||||
bailout("exception handler overflow");
|
||||
@ -412,7 +412,7 @@ int LIR_Assembler::emit_exception_handler() {
|
||||
// search an exception handler (rax: exception oop, rdx: throwing pc)
|
||||
__ call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id)));
|
||||
__ should_not_reach_here();
|
||||
guarantee(code_offset() - offset <= exception_handler_size, "overflow");
|
||||
guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
|
||||
__ end_a_stub();
|
||||
|
||||
return offset;
|
||||
@ -490,7 +490,7 @@ int LIR_Assembler::emit_deopt_handler() {
|
||||
__ nop();
|
||||
|
||||
// generate code for exception handler
|
||||
address handler_base = __ start_a_stub(deopt_handler_size);
|
||||
address handler_base = __ start_a_stub(deopt_handler_size());
|
||||
if (handler_base == NULL) {
|
||||
// not enough space left for the handler
|
||||
bailout("deopt handler overflow");
|
||||
@ -502,7 +502,7 @@ int LIR_Assembler::emit_deopt_handler() {
|
||||
|
||||
__ pushptr(here.addr());
|
||||
__ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
|
||||
guarantee(code_offset() - offset <= deopt_handler_size, "overflow");
|
||||
guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
|
||||
__ end_a_stub();
|
||||
|
||||
return offset;
|
||||
@ -2805,7 +2805,7 @@ void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) {
|
||||
|
||||
void LIR_Assembler::emit_static_call_stub() {
|
||||
address call_pc = __ pc();
|
||||
address stub = __ start_a_stub(call_stub_size);
|
||||
address stub = __ start_a_stub(call_stub_size());
|
||||
if (stub == NULL) {
|
||||
bailout("static call stub overflow");
|
||||
return;
|
||||
@ -2816,14 +2816,24 @@ void LIR_Assembler::emit_static_call_stub() {
|
||||
// make sure that the displacement word of the call ends up word aligned
|
||||
__ align(BytesPerWord, __ offset() + NativeMovConstReg::instruction_size + NativeCall::displacement_offset);
|
||||
}
|
||||
__ relocate(static_stub_Relocation::spec(call_pc));
|
||||
__ relocate(static_stub_Relocation::spec(call_pc, false /* is_aot */));
|
||||
__ mov_metadata(rbx, (Metadata*)NULL);
|
||||
// must be set to -1 at code generation time
|
||||
assert(!os::is_MP() || ((__ offset() + 1) % BytesPerWord) == 0, "must be aligned on MP");
|
||||
// On 64bit this will die since it will take a movq & jmp, must be only a jmp
|
||||
__ jump(RuntimeAddress(__ pc()));
|
||||
|
||||
assert(__ offset() - start <= call_stub_size, "stub too big");
|
||||
if (UseAOT) {
|
||||
// Trampoline to aot code
|
||||
__ relocate(static_stub_Relocation::spec(call_pc, true /* is_aot */));
|
||||
#ifdef _LP64
|
||||
__ mov64(rax, CONST64(0)); // address is zapped till fixup time.
|
||||
#else
|
||||
__ movl(rax, 0xdeadffff); // address is zapped till fixup time.
|
||||
#endif
|
||||
__ jmp(rax);
|
||||
}
|
||||
assert(__ offset() - start <= call_stub_size(), "stub too big");
|
||||
__ end_a_stub();
|
||||
}
|
||||
|
||||
|
||||
@ -47,6 +47,14 @@
|
||||
void type_profile_helper(Register mdo,
|
||||
ciMethodData *md, ciProfileData *data,
|
||||
Register recv, Label* update_done);
|
||||
|
||||
enum {
|
||||
_call_stub_size = NOT_LP64(15) LP64_ONLY(28),
|
||||
_call_aot_stub_size = NOT_LP64(7) LP64_ONLY(12),
|
||||
_exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
|
||||
_deopt_handler_size = NOT_LP64(10) LP64_ONLY(17)
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
void store_parameter(Register r, int offset_from_esp_in_words);
|
||||
@ -54,9 +62,4 @@ public:
|
||||
void store_parameter(jobject c, int offset_from_esp_in_words);
|
||||
void store_parameter(Metadata* c, int offset_from_esp_in_words);
|
||||
|
||||
enum { call_stub_size = NOT_LP64(15) LP64_ONLY(28),
|
||||
exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
|
||||
deopt_handler_size = NOT_LP64(10) LP64_ONLY(17)
|
||||
};
|
||||
|
||||
#endif // CPU_X86_VM_C1_LIRASSEMBLER_X86_HPP
|
||||
|
||||
120
hotspot/src/cpu/x86/vm/compiledIC_aot_x86_64.cpp
Normal file
120
hotspot/src/cpu/x86/vm/compiledIC_aot_x86_64.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "aot/compiledIC_aot.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
|
||||
void CompiledDirectStaticCall::set_to_far(const methodHandle& callee, address entry) {
|
||||
address stub = find_stub(true /* is_far */);
|
||||
guarantee(stub != NULL, "stub not found");
|
||||
|
||||
if (TraceICs) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_far %s",
|
||||
p2i(instruction_address()),
|
||||
callee->name_and_sig_as_C_string());
|
||||
}
|
||||
|
||||
// Creation also verifies the object.
|
||||
// mov rax,imm_aot_addr
|
||||
// jmp rax
|
||||
NativeMovConstReg* destination_holder = nativeMovConstReg_at(stub);
|
||||
|
||||
#ifdef ASSERT
|
||||
// read the value once
|
||||
intptr_t data = destination_holder->data();
|
||||
assert(data == 0 || data == (intptr_t)entry,
|
||||
"MT-unsafe modification of inline cache");
|
||||
#endif
|
||||
|
||||
// Update stub.
|
||||
destination_holder->set_data((intptr_t)entry);
|
||||
|
||||
// Update jump to call.
|
||||
set_destination_mt_safe(stub);
|
||||
}
|
||||
|
||||
void CompiledPltStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
|
||||
address stub = find_stub();
|
||||
guarantee(stub != NULL, "stub not found");
|
||||
if (TraceICs) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("CompiledPltStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
|
||||
p2i(instruction_address()),
|
||||
callee->name_and_sig_as_C_string());
|
||||
}
|
||||
|
||||
// Creation also verifies the object.
|
||||
NativeLoadGot* method_loader = nativeLoadGot_at(stub);
|
||||
NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address());
|
||||
|
||||
intptr_t data = method_loader->data();
|
||||
address destination = jump->destination();
|
||||
assert(data == 0 || data == (intptr_t)callee(),
|
||||
"a) MT-unsafe modification of inline cache");
|
||||
assert(destination == (address)-1 || destination == entry,
|
||||
"b) MT-unsafe modification of inline cache");
|
||||
|
||||
// Update stub.
|
||||
method_loader->set_data((intptr_t)callee());
|
||||
jump->set_jump_destination(entry);
|
||||
|
||||
// Update jump to call.
|
||||
set_destination_mt_safe(stub);
|
||||
}
|
||||
|
||||
#ifdef NEVER_CALLED
|
||||
void CompiledPltStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
|
||||
// Reset stub.
|
||||
address stub = static_stub->addr();
|
||||
assert(stub != NULL, "stub not found");
|
||||
// Creation also verifies the object.
|
||||
NativeLoadGot* method_loader = nativeLoadGot_at(stub);
|
||||
NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address());
|
||||
method_loader->set_data(0);
|
||||
jump->set_jump_destination((address)-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
void CompiledPltStaticCall::verify() {
|
||||
// Verify call.
|
||||
_call->verify();
|
||||
|
||||
#ifdef ASSERT
|
||||
CodeBlob *cb = CodeCache::find_blob_unsafe((address) _call);
|
||||
assert(cb && cb->is_aot(), "CompiledPltStaticCall can only be used on AOTCompiledMethod");
|
||||
#endif
|
||||
|
||||
// Verify stub.
|
||||
address stub = find_stub();
|
||||
assert(stub != NULL, "no stub found for static call");
|
||||
// Creation also verifies the object.
|
||||
NativeLoadGot* method_loader = nativeLoadGot_at(stub);
|
||||
NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address());
|
||||
// Verify state.
|
||||
assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
@ -24,6 +24,7 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/compiledIC.hpp"
|
||||
#include "code/icBuffer.hpp"
|
||||
#include "code/nmethod.hpp"
|
||||
@ -53,7 +54,7 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark)
|
||||
return NULL; // CodeBuffer::expand failed.
|
||||
}
|
||||
// Static stub relocation stores the instruction address of the call.
|
||||
__ relocate(static_stub_Relocation::spec(mark), Assembler::imm_operand);
|
||||
__ relocate(static_stub_Relocation::spec(mark, false), Assembler::imm_operand);
|
||||
// Static stub relocation also tags the Method* in the code-stream.
|
||||
__ mov_metadata(rbx, (Metadata*) NULL); // Method is zapped till fixup time.
|
||||
// This is recognized as unresolved by relocs/nativeinst/ic code.
|
||||
@ -77,13 +78,73 @@ int CompiledStaticCall::reloc_to_interp_stub() {
|
||||
return 4; // 3 in emit_to_interp_stub + 1 in emit_call
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
|
||||
address stub = find_stub();
|
||||
#if INCLUDE_AOT
|
||||
#define __ _masm.
|
||||
void CompiledStaticCall::emit_to_aot_stub(CodeBuffer &cbuf, address mark) {
|
||||
if (!UseAOT) {
|
||||
return;
|
||||
}
|
||||
// Stub is fixed up when the corresponding call is converted from
|
||||
// calling compiled code to calling aot code.
|
||||
// movq rax, imm64_aot_code_address
|
||||
// jmp rax
|
||||
|
||||
if (mark == NULL) {
|
||||
mark = cbuf.insts_mark(); // Get mark within main instrs section.
|
||||
}
|
||||
|
||||
// Note that the code buffer's insts_mark is always relative to insts.
|
||||
// That's why we must use the macroassembler to generate a stub.
|
||||
MacroAssembler _masm(&cbuf);
|
||||
|
||||
address base =
|
||||
__ start_a_stub(to_aot_stub_size());
|
||||
guarantee(base != NULL, "out of space");
|
||||
|
||||
// Static stub relocation stores the instruction address of the call.
|
||||
__ relocate(static_stub_Relocation::spec(mark, true /* is_aot */), Assembler::imm_operand);
|
||||
// Load destination AOT code address.
|
||||
#ifdef _LP64
|
||||
__ mov64(rax, CONST64(0)); // address is zapped till fixup time.
|
||||
#else
|
||||
__ movl(rax, 0); // address is zapped till fixup time.
|
||||
#endif
|
||||
// This is recognized as unresolved by relocs/nativeinst/ic code.
|
||||
__ jmp(rax);
|
||||
|
||||
assert(__ pc() - base <= to_aot_stub_size(), "wrong stub size");
|
||||
|
||||
// Update current stubs pointer and restore insts_end.
|
||||
__ end_a_stub();
|
||||
}
|
||||
#undef __
|
||||
|
||||
int CompiledStaticCall::to_aot_stub_size() {
|
||||
if (UseAOT) {
|
||||
return NOT_LP64(7) // movl; jmp
|
||||
LP64_ONLY(12); // movq (1+1+8); jmp (2)
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Relocation entries for call stub, compiled java to aot.
|
||||
int CompiledStaticCall::reloc_to_aot_stub() {
|
||||
if (UseAOT) {
|
||||
return 2; // 1 in emit_to_aot_stub + 1 in emit_call
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_AOT
|
||||
|
||||
void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
|
||||
address stub = find_stub(false /* is_aot */);
|
||||
guarantee(stub != NULL, "stub not found");
|
||||
|
||||
if (TraceICs) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
|
||||
tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
|
||||
p2i(instruction_address()),
|
||||
callee->name_and_sig_as_C_string());
|
||||
}
|
||||
@ -110,7 +171,7 @@ void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry)
|
||||
set_destination_mt_safe(stub);
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
|
||||
// Reset stub.
|
||||
address stub = static_stub->addr();
|
||||
@ -118,8 +179,10 @@ void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub)
|
||||
// Creation also verifies the object.
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
|
||||
method_holder->set_data(0);
|
||||
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
|
||||
jump->set_jump_destination((address)-1);
|
||||
if (!static_stub->is_aot()) {
|
||||
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
|
||||
jump->set_jump_destination((address)-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -127,15 +190,20 @@ void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub)
|
||||
// Non-product mode code
|
||||
#ifndef PRODUCT
|
||||
|
||||
void CompiledStaticCall::verify() {
|
||||
void CompiledDirectStaticCall::verify() {
|
||||
// Verify call.
|
||||
NativeCall::verify();
|
||||
_call->verify();
|
||||
if (os::is_MP()) {
|
||||
verify_alignment();
|
||||
_call->verify_alignment();
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
CodeBlob *cb = CodeCache::find_blob_unsafe((address) _call);
|
||||
assert(cb && !cb->is_aot(), "CompiledDirectStaticCall cannot be used on AOTCompiledMethod");
|
||||
#endif
|
||||
|
||||
// Verify stub.
|
||||
address stub = find_stub();
|
||||
address stub = find_stub(false /* is_aot */);
|
||||
assert(stub != NULL, "no stub found for static call");
|
||||
// Creation also verifies the object.
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
|
||||
|
||||
@ -33,12 +33,18 @@
|
||||
#include "oops/oop.inline.hpp"
|
||||
|
||||
int InlineCacheBuffer::ic_stub_code_size() {
|
||||
return NativeMovConstReg::instruction_size +
|
||||
NativeJump::instruction_size +
|
||||
1;
|
||||
// so that code_end can be set in CodeBuffer
|
||||
// 64bit 16 = 5 + 10 bytes + 1 byte
|
||||
// 32bit 11 = 10 bytes + 1 byte
|
||||
// Worst case, if destination is not a near call:
|
||||
// lea rax, lit1
|
||||
// lea scratch, lit2
|
||||
// jmp scratch
|
||||
|
||||
// Best case
|
||||
// lea rax, lit1
|
||||
// jmp lit2
|
||||
|
||||
int best = NativeMovConstReg::instruction_size + NativeJump::instruction_size;
|
||||
int worst = 2 * NativeMovConstReg::instruction_size + 3;
|
||||
return MAX2(best, worst);
|
||||
}
|
||||
|
||||
|
||||
@ -59,8 +65,16 @@ void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, void* cached
|
||||
|
||||
address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) {
|
||||
NativeMovConstReg* move = nativeMovConstReg_at(code_begin); // creation also verifies the object
|
||||
NativeJump* jump = nativeJump_at(move->next_instruction_address());
|
||||
return jump->jump_destination();
|
||||
address jmp = move->next_instruction_address();
|
||||
NativeInstruction* ni = nativeInstruction_at(jmp);
|
||||
if (ni->is_jump()) {
|
||||
NativeJump* jump = nativeJump_at(jmp);
|
||||
return jump->jump_destination();
|
||||
} else {
|
||||
assert(ni->is_far_jump(), "unexpected instruction");
|
||||
NativeFarJump* jump = nativeFarJump_at(jmp);
|
||||
return jump->jump_destination();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -68,7 +82,14 @@ void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) {
|
||||
// creation also verifies the object
|
||||
NativeMovConstReg* move = nativeMovConstReg_at(code_begin);
|
||||
// Verifies the jump
|
||||
NativeJump* jump = nativeJump_at(move->next_instruction_address());
|
||||
address jmp = move->next_instruction_address();
|
||||
NativeInstruction* ni = nativeInstruction_at(jmp);
|
||||
if (ni->is_jump()) {
|
||||
NativeJump* jump = nativeJump_at(jmp);
|
||||
} else {
|
||||
assert(ni->is_far_jump(), "unexpected instruction");
|
||||
NativeFarJump* jump = nativeFarJump_at(jmp);
|
||||
}
|
||||
void* o = (void*)move->data();
|
||||
return o;
|
||||
}
|
||||
|
||||
@ -39,6 +39,124 @@ void NativeInstruction::wrote(int offset) {
|
||||
ICache::invalidate_word(addr_at(offset));
|
||||
}
|
||||
|
||||
void NativeLoadGot::report_and_fail() const {
|
||||
tty->print_cr("Addr: " INTPTR_FORMAT, p2i(instruction_address()));
|
||||
fatal("not a indirect rip mov to rbx");
|
||||
}
|
||||
|
||||
void NativeLoadGot::verify() const {
|
||||
if (has_rex) {
|
||||
int rex = ubyte_at(0);
|
||||
if (rex != rex_prefix) {
|
||||
report_and_fail();
|
||||
}
|
||||
}
|
||||
|
||||
int inst = ubyte_at(rex_size);
|
||||
if (inst != instruction_code) {
|
||||
report_and_fail();
|
||||
}
|
||||
int modrm = ubyte_at(rex_size + 1);
|
||||
if (modrm != modrm_rbx_code && modrm != modrm_rax_code) {
|
||||
report_and_fail();
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t NativeLoadGot::data() const {
|
||||
return *(intptr_t *) got_address();
|
||||
}
|
||||
|
||||
address NativePltCall::destination() const {
|
||||
NativeGotJump* jump = nativeGotJump_at(plt_jump());
|
||||
return jump->destination();
|
||||
}
|
||||
|
||||
address NativePltCall::plt_entry() const {
|
||||
return return_address() + displacement();
|
||||
}
|
||||
|
||||
address NativePltCall::plt_jump() const {
|
||||
address entry = plt_entry();
|
||||
// Virtual PLT code has move instruction first
|
||||
if (((NativeGotJump*)entry)->is_GotJump()) {
|
||||
return entry;
|
||||
} else {
|
||||
return nativeLoadGot_at(entry)->next_instruction_address();
|
||||
}
|
||||
}
|
||||
|
||||
address NativePltCall::plt_load_got() const {
|
||||
address entry = plt_entry();
|
||||
if (!((NativeGotJump*)entry)->is_GotJump()) {
|
||||
// Virtual PLT code has move instruction first
|
||||
return entry;
|
||||
} else {
|
||||
// Static PLT code has move instruction second (from c2i stub)
|
||||
return nativeGotJump_at(entry)->next_instruction_address();
|
||||
}
|
||||
}
|
||||
|
||||
address NativePltCall::plt_c2i_stub() const {
|
||||
address entry = plt_load_got();
|
||||
// This method should be called only for static calls which has C2I stub.
|
||||
NativeLoadGot* load = nativeLoadGot_at(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
address NativePltCall::plt_resolve_call() const {
|
||||
NativeGotJump* jump = nativeGotJump_at(plt_jump());
|
||||
address entry = jump->next_instruction_address();
|
||||
if (((NativeGotJump*)entry)->is_GotJump()) {
|
||||
return entry;
|
||||
} else {
|
||||
// c2i stub 2 instructions
|
||||
entry = nativeLoadGot_at(entry)->next_instruction_address();
|
||||
return nativeGotJump_at(entry)->next_instruction_address();
|
||||
}
|
||||
}
|
||||
|
||||
void NativePltCall::reset_to_plt_resolve_call() {
|
||||
set_destination_mt_safe(plt_resolve_call());
|
||||
}
|
||||
|
||||
void NativePltCall::set_destination_mt_safe(address dest) {
|
||||
// rewriting the value in the GOT, it should always be aligned
|
||||
NativeGotJump* jump = nativeGotJump_at(plt_jump());
|
||||
address* got = (address *) jump->got_address();
|
||||
*got = dest;
|
||||
}
|
||||
|
||||
void NativePltCall::set_stub_to_clean() {
|
||||
NativeLoadGot* method_loader = nativeLoadGot_at(plt_c2i_stub());
|
||||
NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address());
|
||||
method_loader->set_data(0);
|
||||
jump->set_jump_destination((address)-1);
|
||||
}
|
||||
|
||||
void NativePltCall::verify() const {
|
||||
// Make sure code pattern is actually a call rip+off32 instruction.
|
||||
int inst = ubyte_at(0);
|
||||
if (inst != instruction_code) {
|
||||
tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", p2i(instruction_address()),
|
||||
inst);
|
||||
fatal("not a call rip+off32");
|
||||
}
|
||||
}
|
||||
|
||||
address NativeGotJump::destination() const {
|
||||
address *got_entry = (address *) got_address();
|
||||
return *got_entry;
|
||||
}
|
||||
|
||||
void NativeGotJump::verify() const {
|
||||
int inst = ubyte_at(0);
|
||||
if (inst != instruction_code) {
|
||||
tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", p2i(instruction_address()),
|
||||
inst);
|
||||
fatal("not a indirect rip jump");
|
||||
}
|
||||
}
|
||||
|
||||
void NativeCall::verify() {
|
||||
// Make sure code pattern is actually a call imm32 instruction.
|
||||
int inst = ubyte_at(0);
|
||||
@ -422,7 +540,12 @@ void NativeLoadAddress::print() {
|
||||
|
||||
void NativeJump::verify() {
|
||||
if (*(u_char*)instruction_address() != instruction_code) {
|
||||
fatal("not a jump instruction");
|
||||
// far jump
|
||||
NativeMovConstReg* mov = nativeMovConstReg_at(instruction_address());
|
||||
NativeInstruction* jmp = nativeInstruction_at(mov->next_instruction_address());
|
||||
if (!jmp->is_jump_reg()) {
|
||||
fatal("not a jump instruction");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,6 +637,20 @@ void NativeJump::patch_verified_entry(address entry, address verified_entry, add
|
||||
|
||||
}
|
||||
|
||||
address NativeFarJump::jump_destination() const {
|
||||
NativeMovConstReg* mov = nativeMovConstReg_at(addr_at(0));
|
||||
return (address)mov->data();
|
||||
}
|
||||
|
||||
void NativeFarJump::verify() {
|
||||
if (is_far_jump()) {
|
||||
NativeMovConstReg* mov = nativeMovConstReg_at(addr_at(0));
|
||||
NativeInstruction* jmp = nativeInstruction_at(mov->next_instruction_address());
|
||||
if (jmp->is_jump_reg()) return;
|
||||
}
|
||||
fatal("not a jump instruction");
|
||||
}
|
||||
|
||||
void NativePopReg::insert(address code_pos, Register reg) {
|
||||
assert(reg->encoding() < 8, "no space for REX");
|
||||
assert(NativePopReg::instruction_size == sizeof(char), "right address unit for update");
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
// - - NativeMovRegMem
|
||||
// - - NativeMovRegMemPatching
|
||||
// - - NativeJump
|
||||
// - - NativeFarJump
|
||||
// - - NativeIllegalOpCode
|
||||
// - - NativeGeneralJump
|
||||
// - - NativeReturn
|
||||
@ -63,6 +64,8 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC {
|
||||
inline bool is_illegal();
|
||||
inline bool is_return();
|
||||
inline bool is_jump();
|
||||
inline bool is_jump_reg();
|
||||
inline bool is_far_jump();
|
||||
inline bool is_cond_jump();
|
||||
inline bool is_safepoint_poll();
|
||||
inline bool is_mov_literal64();
|
||||
@ -105,6 +108,47 @@ inline NativeInstruction* nativeInstruction_at(address address) {
|
||||
return inst;
|
||||
}
|
||||
|
||||
class NativePltCall: public NativeInstruction {
|
||||
public:
|
||||
enum Intel_specific_constants {
|
||||
instruction_code = 0xE8,
|
||||
instruction_size = 5,
|
||||
instruction_offset = 0,
|
||||
displacement_offset = 1,
|
||||
return_address_offset = 5
|
||||
};
|
||||
address instruction_address() const { return addr_at(instruction_offset); }
|
||||
address next_instruction_address() const { return addr_at(return_address_offset); }
|
||||
address displacement_address() const { return addr_at(displacement_offset); }
|
||||
int displacement() const { return (jint) int_at(displacement_offset); }
|
||||
address return_address() const { return addr_at(return_address_offset); }
|
||||
address destination() const;
|
||||
address plt_entry() const;
|
||||
address plt_jump() const;
|
||||
address plt_load_got() const;
|
||||
address plt_resolve_call() const;
|
||||
address plt_c2i_stub() const;
|
||||
void set_stub_to_clean();
|
||||
|
||||
void reset_to_plt_resolve_call();
|
||||
void set_destination_mt_safe(address dest);
|
||||
|
||||
void verify() const;
|
||||
};
|
||||
|
||||
inline NativePltCall* nativePltCall_at(address address) {
|
||||
NativePltCall* call = (NativePltCall*) address;
|
||||
#ifdef ASSERT
|
||||
call->verify();
|
||||
#endif
|
||||
return call;
|
||||
}
|
||||
|
||||
inline NativePltCall* nativePltCall_before(address addr) {
|
||||
address at = addr - NativePltCall::instruction_size;
|
||||
return nativePltCall_at(at);
|
||||
}
|
||||
|
||||
inline NativeCall* nativeCall_at(address address);
|
||||
// The NativeCall is an abstraction for accessing/manipulating native call imm32/rel32off
|
||||
// instructions (used to manipulate inline caches, primitive & dll calls, etc.).
|
||||
@ -129,9 +173,8 @@ class NativeCall: public NativeInstruction {
|
||||
address destination() const;
|
||||
void set_destination(address dest) {
|
||||
#ifdef AMD64
|
||||
assert((labs((intptr_t) dest - (intptr_t) return_address()) &
|
||||
0xFFFFFFFF00000000) == 0,
|
||||
"must be 32bit offset");
|
||||
intptr_t disp = dest - return_address();
|
||||
guarantee(disp == (intptr_t)(jint)disp, "must be 32-bit offset");
|
||||
#endif // AMD64
|
||||
set_int_at(displacement_offset, dest - return_address());
|
||||
}
|
||||
@ -158,6 +201,13 @@ class NativeCall: public NativeInstruction {
|
||||
nativeCall_at(instr)->destination() == target;
|
||||
}
|
||||
|
||||
#if INCLUDE_AOT
|
||||
static bool is_far_call(address instr, address target) {
|
||||
intptr_t disp = target - (instr + sizeof(int32_t));
|
||||
return !Assembler::is_simm32(disp);
|
||||
}
|
||||
#endif
|
||||
|
||||
// MT-safe patching of a call instruction.
|
||||
static void insert(address code_pos, address entry);
|
||||
|
||||
@ -380,6 +430,51 @@ class NativeLoadAddress: public NativeMovRegMem {
|
||||
}
|
||||
};
|
||||
|
||||
// destination is rbx or rax
|
||||
// mov rbx, [rip + offset]
|
||||
class NativeLoadGot: public NativeInstruction {
|
||||
#ifdef AMD64
|
||||
static const bool has_rex = true;
|
||||
static const int rex_size = 1;
|
||||
#else
|
||||
static const bool has_rex = false;
|
||||
static const int rex_size = 0;
|
||||
#endif
|
||||
public:
|
||||
enum Intel_specific_constants {
|
||||
rex_prefix = 0x48,
|
||||
instruction_code = 0x8b,
|
||||
modrm_rbx_code = 0x1d,
|
||||
modrm_rax_code = 0x05,
|
||||
instruction_length = 6 + rex_size,
|
||||
offset_offset = 2 + rex_size
|
||||
};
|
||||
|
||||
address instruction_address() const { return addr_at(0); }
|
||||
address rip_offset_address() const { return addr_at(offset_offset); }
|
||||
int rip_offset() const { return int_at(offset_offset); }
|
||||
address return_address() const { return addr_at(instruction_length); }
|
||||
address got_address() const { return return_address() + rip_offset(); }
|
||||
address next_instruction_address() const { return return_address(); }
|
||||
intptr_t data() const;
|
||||
void set_data(intptr_t data) {
|
||||
intptr_t *addr = (intptr_t *) got_address();
|
||||
*addr = data;
|
||||
}
|
||||
|
||||
void verify() const;
|
||||
private:
|
||||
void report_and_fail() const;
|
||||
};
|
||||
|
||||
inline NativeLoadGot* nativeLoadGot_at(address addr) {
|
||||
NativeLoadGot* load = (NativeLoadGot*) addr;
|
||||
#ifdef ASSERT
|
||||
load->verify();
|
||||
#endif
|
||||
return load;
|
||||
}
|
||||
|
||||
// jump rel32off
|
||||
|
||||
class NativeJump: public NativeInstruction {
|
||||
@ -440,6 +535,29 @@ inline NativeJump* nativeJump_at(address address) {
|
||||
return jump;
|
||||
}
|
||||
|
||||
// far jump reg
|
||||
class NativeFarJump: public NativeInstruction {
|
||||
public:
|
||||
address jump_destination() const;
|
||||
|
||||
// Creation
|
||||
inline friend NativeFarJump* nativeFarJump_at(address address);
|
||||
|
||||
void verify();
|
||||
|
||||
// Unit testing stuff
|
||||
static void test() {}
|
||||
|
||||
};
|
||||
|
||||
inline NativeFarJump* nativeFarJump_at(address address) {
|
||||
NativeFarJump* jump = (NativeFarJump*)(address);
|
||||
#ifdef ASSERT
|
||||
jump->verify();
|
||||
#endif
|
||||
return jump;
|
||||
}
|
||||
|
||||
// Handles all kinds of jump on Intel. Long/far, conditional/unconditional
|
||||
class NativeGeneralJump: public NativeInstruction {
|
||||
public:
|
||||
@ -473,6 +591,36 @@ inline NativeGeneralJump* nativeGeneralJump_at(address address) {
|
||||
return jump;
|
||||
}
|
||||
|
||||
class NativeGotJump: public NativeInstruction {
|
||||
public:
|
||||
enum Intel_specific_constants {
|
||||
instruction_code = 0xff,
|
||||
instruction_offset = 0,
|
||||
instruction_size = 6,
|
||||
rip_offset = 2
|
||||
};
|
||||
|
||||
void verify() const;
|
||||
address instruction_address() const { return addr_at(instruction_offset); }
|
||||
address destination() const;
|
||||
address return_address() const { return addr_at(instruction_size); }
|
||||
int got_offset() const { return (jint) int_at(rip_offset); }
|
||||
address got_address() const { return return_address() + got_offset(); }
|
||||
address next_instruction_address() const { return addr_at(instruction_size); }
|
||||
bool is_GotJump() const { return ubyte_at(0) == instruction_code; }
|
||||
|
||||
void set_jump_destination(address dest) {
|
||||
address *got_entry = (address *) got_address();
|
||||
*got_entry = dest;
|
||||
}
|
||||
};
|
||||
|
||||
inline NativeGotJump* nativeGotJump_at(address addr) {
|
||||
NativeGotJump* jump = (NativeGotJump*)(addr);
|
||||
debug_only(jump->verify());
|
||||
return jump;
|
||||
}
|
||||
|
||||
class NativePopReg : public NativeInstruction {
|
||||
public:
|
||||
enum Intel_specific_constants {
|
||||
@ -544,6 +692,12 @@ inline bool NativeInstruction::is_return() { return ubyte_at(0) == NativeR
|
||||
ubyte_at(0) == NativeReturnX::instruction_code; }
|
||||
inline bool NativeInstruction::is_jump() { return ubyte_at(0) == NativeJump::instruction_code ||
|
||||
ubyte_at(0) == 0xEB; /* short jump */ }
|
||||
inline bool NativeInstruction::is_jump_reg() {
|
||||
int pos = 0;
|
||||
if (ubyte_at(0) == Assembler::REX_B) pos = 1;
|
||||
return ubyte_at(pos) == 0xFF && (ubyte_at(pos + 1) & 0xF0) == 0xE0;
|
||||
}
|
||||
inline bool NativeInstruction::is_far_jump() { return is_mov_literal64(); }
|
||||
inline bool NativeInstruction::is_cond_jump() { return (int_at(0) & 0xF0FF) == 0x800F /* long jump */ ||
|
||||
(ubyte_at(0) & 0xF0) == 0x70; /* short jump */ }
|
||||
inline bool NativeInstruction::is_safepoint_poll() {
|
||||
|
||||
@ -800,7 +800,7 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
__ movptr(r11, Address(rbx, in_bytes(Method::from_compiled_offset())));
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI) {
|
||||
if (EnableJVMCI || UseAOT) {
|
||||
// check if this call should be routed towards a specific entry point
|
||||
__ cmpptr(Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), 0);
|
||||
Label no_alternative_target;
|
||||
@ -2758,7 +2758,7 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
// Setup code generation tools
|
||||
int pad = 0;
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI) {
|
||||
if (EnableJVMCI || UseAOT) {
|
||||
pad += 512; // Increase the buffer size when compiling for JVMCI
|
||||
}
|
||||
#endif
|
||||
@ -2832,7 +2832,7 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
int implicit_exception_uncommon_trap_offset = 0;
|
||||
int uncommon_trap_offset = 0;
|
||||
|
||||
if (EnableJVMCI) {
|
||||
if (EnableJVMCI || UseAOT) {
|
||||
implicit_exception_uncommon_trap_offset = __ pc() - start;
|
||||
|
||||
__ pushptr(Address(r15_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset())));
|
||||
@ -2947,7 +2947,7 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
__ reset_last_Java_frame(false);
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI) {
|
||||
if (EnableJVMCI || UseAOT) {
|
||||
__ bind(after_fetch_unroll_info_call);
|
||||
}
|
||||
#endif
|
||||
@ -3112,7 +3112,7 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
_deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words);
|
||||
_deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI) {
|
||||
if (EnableJVMCI || UseAOT) {
|
||||
_deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset);
|
||||
_deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset);
|
||||
}
|
||||
|
||||
@ -256,7 +256,7 @@ address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, i
|
||||
#if INCLUDE_JVMCI
|
||||
// Check if we need to take lock at entry of synchronized method. This can
|
||||
// only occur on method entry so emit it only for vtos with step 0.
|
||||
if (UseJVMCICompiler && state == vtos && step == 0) {
|
||||
if ((UseJVMCICompiler || UseAOT) && state == vtos && step == 0) {
|
||||
Label L;
|
||||
__ cmpb(Address(thread, JavaThread::pending_monitorenter_offset()), 0);
|
||||
__ jcc(Assembler::zero, L);
|
||||
|
||||
@ -2147,6 +2147,9 @@ encode %{
|
||||
ciEnv::current()->record_failure("CodeCache is full");
|
||||
return;
|
||||
}
|
||||
#if INCLUDE_AOT
|
||||
CompiledStaticCall::emit_to_aot_stub(cbuf, mark);
|
||||
#endif
|
||||
}
|
||||
%}
|
||||
|
||||
|
||||
@ -60,11 +60,11 @@ int CompiledStaticCall::reloc_to_interp_stub() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
|
||||
void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
|
||||
ShouldNotReachHere(); // Only needed for COMPILER2.
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
ShouldNotReachHere(); // Only needed for COMPILER2.
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub)
|
||||
// Non-product mode code.
|
||||
#ifndef PRODUCT
|
||||
|
||||
void CompiledStaticCall::verify() {
|
||||
void CompiledDirectStaticCall::verify() {
|
||||
ShouldNotReachHere(); // Only needed for COMPILER2.
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,866 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat;
|
||||
|
||||
import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.tools.jaotc.binformat.Symbol.Binding;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Kind;
|
||||
import jdk.tools.jaotc.binformat.elf.JELFRelocObject;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
|
||||
/**
|
||||
* A format-agnostic container class that holds various components of a binary.
|
||||
*
|
||||
* <p>
|
||||
* This class holds information necessary to create platform-specific binary containers such as
|
||||
* ELFContainer for Linux and Solaris operating systems or yet-to be created MachOContainer for Mac
|
||||
* OS or PEContainer for MS Windows operating systems.
|
||||
*
|
||||
* <p>
|
||||
* Method APIs provided by this class are used to construct and populate platform-independent
|
||||
* contents of a binary as the first step to create a binary representation of code generated by a
|
||||
* compiler backend such as Graal.
|
||||
*
|
||||
* <p>
|
||||
* Methods to record and access code section contents, symbols and relocations are provided.
|
||||
*/
|
||||
public class BinaryContainer implements SymbolTable {
|
||||
|
||||
private final int codeSegmentSize;
|
||||
|
||||
private final int codeEntryAlignment;
|
||||
|
||||
/**
|
||||
* Container holding code bits and any other related information.
|
||||
*/
|
||||
private final CodeContainer codeContainer;
|
||||
|
||||
/**
|
||||
* Container holding external hotspot linkage bits (PLT entries).
|
||||
*/
|
||||
private final CodeContainer extLinkageContainer;
|
||||
|
||||
/**
|
||||
* Container holding global offset data for hotspot linkage.
|
||||
*/
|
||||
private final ByteContainer extLinkageGOTContainer;
|
||||
|
||||
/**
|
||||
* Patched by HotSpot, contains metaspace pointers.
|
||||
*/
|
||||
private final ByteContainer metaspaceGotContainer;
|
||||
|
||||
/**
|
||||
* Patched lazily by hotspot, contains klass/method pointers.
|
||||
*/
|
||||
private final ByteContainer metadataGotContainer;
|
||||
|
||||
/**
|
||||
* BSS container, contains method state array.
|
||||
*/
|
||||
private final ByteContainer methodStateContainer;
|
||||
|
||||
/**
|
||||
* Patched by hotspot, contains java object pointers.
|
||||
*/
|
||||
private final ByteContainer oopGotContainer;
|
||||
|
||||
// Containers holding read-only data
|
||||
private final ReadOnlyDataContainer configContainer;
|
||||
private final ReadOnlyDataContainer metaspaceNamesContainer;
|
||||
private final ReadOnlyDataContainer methodsOffsetsContainer;
|
||||
private final ReadOnlyDataContainer klassesOffsetsContainer;
|
||||
private final ReadOnlyDataContainer klassesDependenciesContainer;
|
||||
private final HeaderContainer headerContainer;
|
||||
private final ReadOnlyDataContainer stubsOffsetsContainer;
|
||||
private final ReadOnlyDataContainer codeSegmentsContainer;
|
||||
|
||||
// This cannot be read only since we need to patch the metadata at runtime..
|
||||
private final ReadOnlyDataContainer methodMetadataContainer;
|
||||
|
||||
/**
|
||||
* Container containing constant data used by code.
|
||||
*/
|
||||
private final ReadOnlyDataContainer constantDataContainer;
|
||||
|
||||
/**
|
||||
* Map holding the Strings table.
|
||||
*/
|
||||
private final Map<String, Integer> offsetStringTable = new HashMap<>();
|
||||
|
||||
private final Map<String, Integer> metaspaceNames = new HashMap<>();
|
||||
|
||||
// List of relocation table entries - (symbolName, relocationInfo)
|
||||
private final Map<String, Symbol> symbolTable = new HashMap<>();
|
||||
private final Map<Symbol, List<Relocation>> relocationTable = new HashMap<>();
|
||||
private final Map<Symbol, Relocation> uniqueRelocationTable = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Mapping of local VM function names to known global symbols generated in the output binary.
|
||||
*/
|
||||
private static final HashMap<String, String> functionNamesToAOTSymbols = new HashMap<>();
|
||||
|
||||
private static final String[][] map = {
|
||||
//@formatter:off
|
||||
{"CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", "_aot_deopt_blob_unpack"},
|
||||
{"CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap", "_aot_deopt_blob_uncommon_trap"},
|
||||
{"CompilerToVM::Data::SharedRuntime_ic_miss_stub", "_aot_ic_miss_stub"},
|
||||
{"CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", "_aot_handle_wrong_method_stub"},
|
||||
{"SharedRuntime::exception_handler_for_return_address", "_aot_exception_handler_for_return_address"},
|
||||
{"SharedRuntime::register_finalizer", "_aot_register_finalizer"},
|
||||
{"SharedRuntime::OSR_migration_end", "_aot_OSR_migration_end"},
|
||||
{"CompilerRuntime::resolve_string_by_symbol", "_aot_resolve_string_by_symbol"},
|
||||
{"CompilerRuntime::resolve_klass_by_symbol", "_aot_resolve_klass_by_symbol"},
|
||||
{"CompilerRuntime::resolve_method_by_symbol_and_load_counters","_aot_resolve_method_by_symbol_and_load_counters"},
|
||||
{"CompilerRuntime::initialize_klass_by_symbol", "_aot_initialize_klass_by_symbol"},
|
||||
{"CompilerRuntime::invocation_event", "_aot_invocation_event"},
|
||||
{"CompilerRuntime::backedge_event", "_aot_backedge_event"},
|
||||
|
||||
{"CompilerToVM::Data::dpow", "_aot_shared_runtime_dpow"},
|
||||
{"CompilerToVM::Data::dexp", "_aot_shared_runtime_dexp"},
|
||||
{"CompilerToVM::Data::dcos", "_aot_shared_runtime_dcos"},
|
||||
{"CompilerToVM::Data::dsin", "_aot_shared_runtime_dsin"},
|
||||
{"CompilerToVM::Data::dtan", "_aot_shared_runtime_dtan"},
|
||||
{"CompilerToVM::Data::dlog", "_aot_shared_runtime_dlog"},
|
||||
{"CompilerToVM::Data::dlog10", "_aot_shared_runtime_dlog10"},
|
||||
|
||||
{"StubRoutines::_jbyte_arraycopy", "_aot_stub_routines_jbyte_arraycopy"},
|
||||
{"StubRoutines::_jshort_arraycopy", "_aot_stub_routines_jshort_arraycopy"},
|
||||
{"StubRoutines::_jint_arraycopy", "_aot_stub_routines_jint_arraycopy"},
|
||||
{"StubRoutines::_jlong_arraycopy", "_aot_stub_routines_jlong_arraycopy"},
|
||||
{"StubRoutines::_oop_arraycopy", "_aot_stub_routines_oop_arraycopy"},
|
||||
{"StubRoutines::_oop_arraycopy_uninit", "_aot_stub_routines_oop_arraycopy_uninit"},
|
||||
|
||||
{"StubRoutines::_jbyte_disjoint_arraycopy", "_aot_stub_routines_jbyte_disjoint_arraycopy"},
|
||||
{"StubRoutines::_jshort_disjoint_arraycopy", "_aot_stub_routines_jshort_disjoint_arraycopy"},
|
||||
{"StubRoutines::_jint_disjoint_arraycopy", "_aot_stub_routines_jint_disjoint_arraycopy"},
|
||||
{"StubRoutines::_jlong_disjoint_arraycopy", "_aot_stub_routines_jlong_disjoint_arraycopy"},
|
||||
{"StubRoutines::_oop_disjoint_arraycopy", "_aot_stub_routines_oop_disjoint_arraycopy"},
|
||||
{"StubRoutines::_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_oop_disjoint_arraycopy_uninit"},
|
||||
|
||||
{"StubRoutines::_arrayof_jbyte_arraycopy", "_aot_stub_routines_arrayof_jbyte_arraycopy"},
|
||||
{"StubRoutines::_arrayof_jshort_arraycopy", "_aot_stub_routines_arrayof_jshort_arraycopy"},
|
||||
{"StubRoutines::_arrayof_jint_arraycopy", "_aot_stub_routines_arrayof_jint_arraycopy"},
|
||||
{"StubRoutines::_arrayof_jlong_arraycopy", "_aot_stub_routines_arrayof_jlong_arraycopy"},
|
||||
{"StubRoutines::_arrayof_oop_arraycopy", "_aot_stub_routines_arrayof_oop_arraycopy"},
|
||||
{"StubRoutines::_arrayof_oop_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_arraycopy_uninit"},
|
||||
|
||||
{"StubRoutines::_arrayof_jbyte_disjoint_arraycopy", "_aot_stub_routines_arrayof_jbyte_disjoint_arraycopy"},
|
||||
{"StubRoutines::_arrayof_jshort_disjoint_arraycopy", "_aot_stub_routines_arrayof_jshort_disjoint_arraycopy"},
|
||||
{"StubRoutines::_arrayof_jint_disjoint_arraycopy", "_aot_stub_routines_arrayof_jint_disjoint_arraycopy"},
|
||||
{"StubRoutines::_arrayof_jlong_disjoint_arraycopy", "_aot_stub_routines_arrayof_jlong_disjoint_arraycopy"},
|
||||
{"StubRoutines::_arrayof_oop_disjoint_arraycopy", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy"},
|
||||
{"StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit"},
|
||||
|
||||
{"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"},
|
||||
|
||||
|
||||
|
||||
|
||||
{"StubRoutines::_aescrypt_encryptBlock", "_aot_stub_routines_aescrypt_encryptBlock"},
|
||||
{"StubRoutines::_aescrypt_decryptBlock", "_aot_stub_routines_aescrypt_decryptBlock"},
|
||||
{"StubRoutines::_cipherBlockChaining_encryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_encryptAESCrypt"},
|
||||
{"StubRoutines::_cipherBlockChaining_decryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_decryptAESCrypt"},
|
||||
{"StubRoutines::_updateBytesCRC32", "_aot_stub_routines_update_bytes_crc32"},
|
||||
{"StubRoutines::_crc_table_adr", "_aot_stub_routines_crc_table_adr"},
|
||||
|
||||
{"StubRoutines::_sha1_implCompress", "_aot_stub_routines_sha1_implCompress" },
|
||||
{"StubRoutines::_sha1_implCompressMB", "_aot_stub_routines_sha1_implCompressMB" },
|
||||
{"StubRoutines::_sha256_implCompress", "_aot_stub_routines_sha256_implCompress" },
|
||||
{"StubRoutines::_sha256_implCompressMB", "_aot_stub_routines_sha256_implCompressMB" },
|
||||
{"StubRoutines::_sha512_implCompress", "_aot_stub_routines_sha512_implCompress" },
|
||||
{"StubRoutines::_sha512_implCompressMB", "_aot_stub_routines_sha512_implCompressMB" },
|
||||
{"StubRoutines::_multiplyToLen", "_aot_stub_routines_multiplyToLen" },
|
||||
|
||||
{"StubRoutines::_counterMode_AESCrypt", "_aot_stub_routines_counterMode_AESCrypt" },
|
||||
{"StubRoutines::_ghash_processBlocks", "_aot_stub_routines_ghash_processBlocks" },
|
||||
{"StubRoutines::_crc32c_table_addr", "_aot_stub_routines_crc32c_table_addr" },
|
||||
{"StubRoutines::_updateBytesCRC32C", "_aot_stub_routines_updateBytesCRC32C" },
|
||||
{"StubRoutines::_updateBytesAdler32", "_aot_stub_routines_updateBytesAdler32" },
|
||||
{"StubRoutines::_squareToLen", "_aot_stub_routines_squareToLen" },
|
||||
{"StubRoutines::_mulAdd", "_aot_stub_routines_mulAdd" },
|
||||
{"StubRoutines::_montgomeryMultiply", "_aot_stub_routines_montgomeryMultiply" },
|
||||
{"StubRoutines::_montgomerySquare", "_aot_stub_routines_montgomerySquare" },
|
||||
{"StubRoutines::_vectorizedMismatch", "_aot_stub_routines_vectorizedMismatch" },
|
||||
|
||||
{"StubRoutines::_throw_delayed_StackOverflowError_entry", "_aot_stub_routines_throw_delayed_StackOverflowError_entry" },
|
||||
|
||||
|
||||
{"os::javaTimeMillis", "_aot_os_javaTimeMillis"},
|
||||
{"os::javaTimeNanos", "_aot_os_javaTimeNanos"},
|
||||
|
||||
{"JVMCIRuntime::monitorenter", "_aot_jvmci_runtime_monitorenter"},
|
||||
{"JVMCIRuntime::monitorexit", "_aot_jvmci_runtime_monitorexit"},
|
||||
{"JVMCIRuntime::log_object", "_aot_jvmci_runtime_log_object"},
|
||||
{"JVMCIRuntime::log_printf", "_aot_jvmci_runtime_log_printf"},
|
||||
{"JVMCIRuntime::vm_message", "_aot_jvmci_runtime_vm_message"},
|
||||
{"JVMCIRuntime::new_instance", "_aot_jvmci_runtime_new_instance"},
|
||||
{"JVMCIRuntime::log_primitive", "_aot_jvmci_runtime_log_primitive"},
|
||||
{"JVMCIRuntime::new_multi_array", "_aot_jvmci_runtime_new_multi_array"},
|
||||
{"JVMCIRuntime::validate_object", "_aot_jvmci_runtime_validate_object"},
|
||||
{"JVMCIRuntime::dynamic_new_array", "_aot_jvmci_runtime_dynamic_new_array"},
|
||||
{"JVMCIRuntime::write_barrier_pre", "_aot_jvmci_runtime_write_barrier_pre"},
|
||||
{"JVMCIRuntime::identity_hash_code", "_aot_jvmci_runtime_identity_hash_code"},
|
||||
{"JVMCIRuntime::write_barrier_post", "_aot_jvmci_runtime_write_barrier_post"},
|
||||
{"JVMCIRuntime::dynamic_new_instance", "_aot_jvmci_runtime_dynamic_new_instance"},
|
||||
{"JVMCIRuntime::thread_is_interrupted", "_aot_jvmci_runtime_thread_is_interrupted"},
|
||||
{"JVMCIRuntime::exception_handler_for_pc", "_aot_jvmci_runtime_exception_handler_for_pc"},
|
||||
{"JVMCIRuntime::test_deoptimize_call_int", "_aot_jvmci_runtime_test_deoptimize_call_int"},
|
||||
|
||||
{"JVMCIRuntime::throw_and_post_jvmti_exception", "_aot_jvmci_runtime_throw_and_post_jvmti_exception"},
|
||||
{"JVMCIRuntime::throw_klass_external_name_exception", "_aot_jvmci_runtime_throw_klass_external_name_exception"},
|
||||
{"JVMCIRuntime::throw_class_cast_exception", "_aot_jvmci_runtime_throw_class_cast_exception"},
|
||||
|
||||
{"JVMCIRuntime::vm_error", "_aot_jvmci_runtime_vm_error"},
|
||||
{"JVMCIRuntime::new_array", "_aot_jvmci_runtime_new_array"}
|
||||
//@formatter:on
|
||||
};
|
||||
|
||||
static {
|
||||
for (String[] entry : map) {
|
||||
functionNamesToAOTSymbols.put(entry[0], entry[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a {@code BinaryContainer} object whose content will be generated in a file with the
|
||||
* prefix {@code prefix}. It also initializes internal code container, symbol table and
|
||||
* relocation tables.
|
||||
*/
|
||||
public BinaryContainer(GraalHotSpotVMConfig config, String jvmVersion) {
|
||||
this.codeSegmentSize = config.codeSegmentSize;
|
||||
this.codeEntryAlignment = config.codeEntryAlignment;
|
||||
|
||||
// read only, code
|
||||
codeContainer = new CodeContainer(".text", this);
|
||||
extLinkageContainer = new CodeContainer(".hotspot.linkage.plt", this);
|
||||
|
||||
// read only, info
|
||||
configContainer = new ReadOnlyDataContainer(".config", this);
|
||||
metaspaceNamesContainer = new ReadOnlyDataContainer(".metaspace.names", this);
|
||||
methodsOffsetsContainer = new ReadOnlyDataContainer(".methods.offsets", this);
|
||||
klassesOffsetsContainer = new ReadOnlyDataContainer(".klasses.offsets", this);
|
||||
klassesDependenciesContainer = new ReadOnlyDataContainer(".klasses.dependencies", this);
|
||||
|
||||
headerContainer = new HeaderContainer(jvmVersion, new ReadOnlyDataContainer(".header", this));
|
||||
stubsOffsetsContainer = new ReadOnlyDataContainer(".stubs.offsets", this);
|
||||
codeSegmentsContainer = new ReadOnlyDataContainer(".code.segments", this);
|
||||
constantDataContainer = new ReadOnlyDataContainer(".method.constdata", this);
|
||||
|
||||
// needs relocation patching at load time by the loader
|
||||
methodMetadataContainer = new ReadOnlyDataContainer(".method.metadata", this);
|
||||
|
||||
// writable sections
|
||||
metaspaceGotContainer = new ByteContainer(".metaspace.got", this);
|
||||
metadataGotContainer = new ByteContainer(".metadata.got", this);
|
||||
methodStateContainer = new ByteContainer(".method.state", this);
|
||||
oopGotContainer = new ByteContainer(".oop.got", this);
|
||||
extLinkageGOTContainer = new ByteContainer(".hotspot.linkage.got", this);
|
||||
|
||||
addGlobalSymbols();
|
||||
|
||||
recordConfiguration(config);
|
||||
}
|
||||
|
||||
private void recordConfiguration(GraalHotSpotVMConfig config) {
|
||||
// @formatter:off
|
||||
boolean[] booleanFlags = { config.cAssertions, // Debug VM
|
||||
config.useCompressedOops,
|
||||
config.useCompressedClassPointers,
|
||||
config.compactFields,
|
||||
config.useG1GC,
|
||||
config.useCMSGC,
|
||||
config.useTLAB,
|
||||
config.useBiasedLocking,
|
||||
TieredAOT.getValue(),
|
||||
config.enableContended,
|
||||
config.restrictContended,
|
||||
};
|
||||
|
||||
int[] intFlags = { config.narrowOopShift,
|
||||
config.narrowKlassShift,
|
||||
config.contendedPaddingWidth,
|
||||
config.fieldsAllocationStyle,
|
||||
config.objectAlignment,
|
||||
config.codeSegmentSize,
|
||||
};
|
||||
// @formatter:on
|
||||
|
||||
byte[] booleanFlagsAsBytes = flagsToByteArray(booleanFlags);
|
||||
int size0 = configContainer.getByteStreamSize();
|
||||
|
||||
// @formatter:off
|
||||
int computedSize = booleanFlagsAsBytes.length * Byte.BYTES + // size of boolean flags
|
||||
intFlags.length * Integer.BYTES + // size of int flags
|
||||
Integer.BYTES; // size of the "computedSize"
|
||||
|
||||
configContainer.appendInt(computedSize).
|
||||
appendInts(intFlags).
|
||||
appendBytes(booleanFlagsAsBytes);
|
||||
// @formatter:on
|
||||
|
||||
int size = configContainer.getByteStreamSize() - size0;
|
||||
assert size == computedSize;
|
||||
}
|
||||
|
||||
private static byte[] flagsToByteArray(boolean[] flags) {
|
||||
byte[] byteArray = new byte[flags.length];
|
||||
for (int i = 0; i < flags.length; ++i) {
|
||||
byteArray[i] = boolToByte(flags[i]);
|
||||
}
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
private static byte boolToByte(boolean flag) {
|
||||
return (byte) (flag ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free some memory.
|
||||
*/
|
||||
public void freeMemory() {
|
||||
offsetStringTable.clear();
|
||||
metaspaceNames.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
* Global symbol names in generated DSO corresponding to VM's symbols. VM needs to look up this
|
||||
* symbol in DSO and link it with VM's corresponding symbol: store VM's symbol address or value
|
||||
* in the named GOT cell.
|
||||
*/
|
||||
|
||||
public String getCardTableAddressSymbolName() {
|
||||
return "_aot_card_table_address";
|
||||
}
|
||||
|
||||
public String getHeapTopAddressSymbolName() {
|
||||
return "_aot_heap_top_address";
|
||||
}
|
||||
|
||||
public String getHeapEndAddressSymbolName() {
|
||||
return "_aot_heap_end_address";
|
||||
}
|
||||
|
||||
public String getCrcTableAddressSymbolName() {
|
||||
return "_aot_stub_routines_crc_table_adr";
|
||||
}
|
||||
|
||||
public String getPollingPageSymbolName() {
|
||||
return "_aot_polling_page";
|
||||
}
|
||||
|
||||
public String getResolveStaticEntrySymbolName() {
|
||||
return "_resolve_static_entry";
|
||||
}
|
||||
|
||||
public String getResolveVirtualEntrySymbolName() {
|
||||
return "_resolve_virtual_entry";
|
||||
}
|
||||
|
||||
public String getResolveOptVirtualEntrySymbolName() {
|
||||
return "_resolve_opt_virtual_entry";
|
||||
}
|
||||
|
||||
public String getNarrowKlassBaseAddressSymbolName() {
|
||||
return "_aot_narrow_klass_base_address";
|
||||
}
|
||||
|
||||
public String getLogOfHeapRegionGrainBytesSymbolName() {
|
||||
return "_aot_log_of_heap_region_grain_bytes";
|
||||
}
|
||||
|
||||
public String getInlineContiguousAllocationSupportedSymbolName() {
|
||||
return "_aot_inline_contiguous_allocation_supported";
|
||||
}
|
||||
|
||||
public int getCodeSegmentSize() {
|
||||
return codeSegmentSize;
|
||||
}
|
||||
|
||||
public int getCodeEntryAlignment() {
|
||||
return codeEntryAlignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the global AOT symbol associated with the function name.
|
||||
*
|
||||
* @param functionName function name
|
||||
* @return AOT symbol for the given function name, or null if there is no mapping.
|
||||
*/
|
||||
public String getAOTSymbolForVMFunctionName(String functionName) {
|
||||
return functionNamesToAOTSymbols.get(functionName);
|
||||
}
|
||||
|
||||
private void addGlobalSymbols() {
|
||||
// Create global symbols for all containers.
|
||||
createContainerSymbol(codeContainer);
|
||||
createContainerSymbol(configContainer);
|
||||
createContainerSymbol(methodsOffsetsContainer);
|
||||
createContainerSymbol(klassesOffsetsContainer);
|
||||
createContainerSymbol(klassesDependenciesContainer);
|
||||
createContainerSymbol(metaspaceGotContainer);
|
||||
createContainerSymbol(metadataGotContainer);
|
||||
createContainerSymbol(methodStateContainer);
|
||||
createContainerSymbol(oopGotContainer);
|
||||
createContainerSymbol(metaspaceNamesContainer);
|
||||
createContainerSymbol(methodMetadataContainer);
|
||||
createContainerSymbol(stubsOffsetsContainer);
|
||||
createContainerSymbol(headerContainer.getContainer());
|
||||
createContainerSymbol(codeSegmentsContainer);
|
||||
|
||||
createGotSymbol(getResolveStaticEntrySymbolName());
|
||||
createGotSymbol(getResolveVirtualEntrySymbolName());
|
||||
createGotSymbol(getResolveOptVirtualEntrySymbolName());
|
||||
createGotSymbol(getCardTableAddressSymbolName());
|
||||
createGotSymbol(getHeapTopAddressSymbolName());
|
||||
createGotSymbol(getHeapEndAddressSymbolName());
|
||||
createGotSymbol(getNarrowKlassBaseAddressSymbolName());
|
||||
createGotSymbol(getPollingPageSymbolName());
|
||||
createGotSymbol(getLogOfHeapRegionGrainBytesSymbolName());
|
||||
createGotSymbol(getInlineContiguousAllocationSupportedSymbolName());
|
||||
|
||||
for (HashMap.Entry<String, String> entry : functionNamesToAOTSymbols.entrySet()) {
|
||||
createGotSymbol(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a global symbol of the form {@code "JVM" + container name}.
|
||||
*
|
||||
* @param container container to create a symbol for
|
||||
*/
|
||||
private static void createContainerSymbol(ByteContainer container) {
|
||||
container.createSymbol(0, Kind.OBJECT, Binding.GLOBAL, 0, "JVM" + container.getContainerName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a global GOT symbol of the form {@code "got." + name}.
|
||||
*
|
||||
* @param name name for the GOT symbol
|
||||
*/
|
||||
private void createGotSymbol(String name) {
|
||||
String s = "got." + name;
|
||||
Symbol gotSymbol = extLinkageGOTContainer.createGotSymbol(s);
|
||||
extLinkageGOTContainer.createSymbol(gotSymbol.getOffset(), Kind.OBJECT, Binding.GLOBAL, 8, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a platform-specific binary file representing the content of the
|
||||
* {@code BinaryContainer} object.
|
||||
*
|
||||
* This method is called after creating and performing any necessary changes to the contents of
|
||||
* code stream, symbol tables and relocation tables is completely finalized
|
||||
*
|
||||
* @param outputFileName name of output file
|
||||
*
|
||||
* @throws IOException in case of file creation failure
|
||||
*/
|
||||
public void createBinary(String outputFileName, String aotVersion) throws IOException {
|
||||
String osName = System.getProperty("os.name");
|
||||
switch (osName) {
|
||||
case "Linux":
|
||||
case "SunOS":
|
||||
JELFRelocObject elfso = new JELFRelocObject(this, outputFileName, aotVersion);
|
||||
elfso.createELFRelocObject(relocationTable, symbolTable.values());
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Unsupported platform: " + osName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add symbol to the symbol table. If the existing symbol is undefined and the specified symbol
|
||||
* is not undefined, replace the existing symbol information with that specified.
|
||||
*
|
||||
* @param symInfo symbol information to be added
|
||||
*/
|
||||
public void addSymbol(Symbol symInfo) {
|
||||
if (symInfo.getName().startsWith("got.") && !(symInfo instanceof GotSymbol)) {
|
||||
throw new InternalError("adding got. without being GotSymbol");
|
||||
}
|
||||
if (symbolTable.containsKey(symInfo.getName())) {
|
||||
throw new InternalError("Symbol: " + symInfo.getName() + " already exists in SymbolTable");
|
||||
} else {
|
||||
// System.out.println("# Symbol [" + name + "] [" + symInfo.getValue() + "] [" +
|
||||
// symInfo.getSection().getContainerName() + "] [" + symInfo.getSize() + "]");
|
||||
symbolTable.put(symInfo.getName(), symInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addStringOffset(String name, Integer offset) {
|
||||
offsetStringTable.put(name, offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add relocation entry for {@code symName}. Multiple relocation entries for a given symbol may
|
||||
* exist.
|
||||
*
|
||||
* @param info relocation information to be added
|
||||
*/
|
||||
public void addRelocation(Relocation info) {
|
||||
// System.out.println("# Relocation [" + symName + "] [" + info.getOffset() + "] [" +
|
||||
// info.getSection().getContainerName() + "] [" + info.getSymbol().getName() + "] [" +
|
||||
// info.getSymbol().getOffset() + " @ " + info.getSymbol().getSection().getContainerName() +
|
||||
// "]");
|
||||
if (relocationTable.containsKey(info.getSymbol())) {
|
||||
relocationTable.get(info.getSymbol()).add(info);
|
||||
} else if (uniqueRelocationTable.containsKey(info.getSymbol())) {
|
||||
// promote
|
||||
ArrayList<Relocation> list = new ArrayList<>(2);
|
||||
list.add(uniqueRelocationTable.get(info.getSymbol()));
|
||||
list.add(info);
|
||||
relocationTable.put(info.getSymbol(), list);
|
||||
uniqueRelocationTable.remove(info.getSymbol());
|
||||
} else {
|
||||
uniqueRelocationTable.put(info.getSymbol(), info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get symbol with name {@code symName}.
|
||||
*
|
||||
* @param symName name of symbol for which symbol table information is being queried
|
||||
* @return success or failure of insertion operation
|
||||
*/
|
||||
@Override
|
||||
public Symbol getSymbol(String symName) {
|
||||
return symbolTable.get(symName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol createSymbol(int offset, Kind kind, Binding binding, int size, String name) {
|
||||
if (kind != Kind.NATIVE_FUNCTION) {
|
||||
throw new UnsupportedOperationException("Must be external functions: " + name);
|
||||
}
|
||||
Symbol symbol = new Symbol(offset, kind, binding, null, size, name);
|
||||
addSymbol(symbol);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get offset in got section with name {@code symName}.
|
||||
*
|
||||
* @param name for which String table information is being queried
|
||||
* @return success or failure of insertion operation
|
||||
*/
|
||||
public Integer getStringOffset(String name) {
|
||||
return offsetStringTable.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert {@code targetCode} to code stream with {@code size} at {@code offset}.
|
||||
*
|
||||
* @param targetCode byte array of native code
|
||||
* @param offset offset at which {@code targetCode} is to be inserted
|
||||
* @param size size of {@code targetCode}
|
||||
*/
|
||||
private static void appendBytes(ByteContainer byteContainer, byte[] targetCode, int offset, int size) {
|
||||
byteContainer.appendBytes(targetCode, offset, size);
|
||||
}
|
||||
|
||||
public void appendCodeBytes(byte[] targetCode, int offset, int size) {
|
||||
appendBytes(codeContainer, targetCode, offset, size);
|
||||
}
|
||||
|
||||
public void appendIntToCode(int value) {
|
||||
codeContainer.appendInt(value);
|
||||
}
|
||||
|
||||
public int appendExtLinkageGotBytes(byte[] bytes, int offset, int size) {
|
||||
int startOffset = extLinkageGOTContainer.getByteStreamSize();
|
||||
appendBytes(extLinkageGOTContainer, bytes, offset, size);
|
||||
return startOffset;
|
||||
}
|
||||
|
||||
public int appendMetaspaceGotBytes(byte[] bytes, int offset, int size) {
|
||||
int startOffset = metaspaceGotContainer.getByteStreamSize();
|
||||
appendBytes(metaspaceGotContainer, bytes, offset, size);
|
||||
return startOffset;
|
||||
}
|
||||
|
||||
public void addMetadataGotEntry(int offset) {
|
||||
metadataGotContainer.appendLong(offset);
|
||||
}
|
||||
|
||||
public int addMetaspaceName(String name) {
|
||||
Integer value = metaspaceNames.get(name);
|
||||
if (value != null) {
|
||||
return value.intValue();
|
||||
}
|
||||
// Get the current length of the stubsNameContainer
|
||||
// align on 8-byte boundary
|
||||
int nameOffset = alignUp(metaspaceNamesContainer, 8);
|
||||
|
||||
try {
|
||||
// Add the name of the symbol to the .stubs.names section
|
||||
// Modify them to sequence of utf8 strings with length:
|
||||
// "<u2_size>Ljava/lang/ThreadGroup;<u2_size>addUnstarted<u2_size>()V"
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
DataOutputStream out = new DataOutputStream(bout);
|
||||
int len = name.length();
|
||||
if (name.startsWith("Stub")) { // Stub
|
||||
out.writeUTF(name);
|
||||
} else { // Method or Klass
|
||||
int parenthesesIndex = name.lastIndexOf('(', len - 1);
|
||||
if (parenthesesIndex > 0) { // Method name
|
||||
int dotIndex = name.lastIndexOf('.', parenthesesIndex - 1);
|
||||
assert dotIndex > 0 : "method's full name should have '.' : " + name;
|
||||
String klassName = name.substring(0, dotIndex);
|
||||
out.writeUTF(klassName);
|
||||
String methodName = name.substring(dotIndex + 1, parenthesesIndex);
|
||||
out.writeUTF(methodName);
|
||||
String signature = name.substring(parenthesesIndex, len);
|
||||
out.writeUTF(signature);
|
||||
} else {
|
||||
out.writeUTF(name); // Klass
|
||||
}
|
||||
}
|
||||
out.writeShort(0); // Terminate by 0.
|
||||
byte[] b = bout.toByteArray();
|
||||
metaspaceNamesContainer.appendBytes(b, 0, b.length);
|
||||
|
||||
metaspaceNames.put(name, nameOffset);
|
||||
return nameOffset;
|
||||
} catch (IOException e) {
|
||||
throw new InternalError("Failed to append bytes to stubs sections", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to
|
||||
* patch.
|
||||
*
|
||||
* @param oopName name of the oop symbol
|
||||
*/
|
||||
public Integer addOopSymbol(String oopName) {
|
||||
Integer oopGotOffset = getStringOffset(oopName);
|
||||
if (oopGotOffset != null) {
|
||||
return oopGotOffset;
|
||||
}
|
||||
return newOopSymbol(oopName);
|
||||
}
|
||||
|
||||
private Integer newOopSymbol(String oopName) {
|
||||
// Reference to String resolution (ldc).
|
||||
int offset = oopGotContainer.getByteStreamSize();
|
||||
String gotName = "got.ldc." + offset;
|
||||
Symbol relocationSymbol = oopGotContainer.createGotSymbol(gotName);
|
||||
|
||||
if (offset != relocationSymbol.getOffset()) {
|
||||
throw new InternalError("offset must equal! (" + offset + " vs " + relocationSymbol.getOffset());
|
||||
}
|
||||
|
||||
addStringOffset(oopName, relocationSymbol.getOffset());
|
||||
return relocationSymbol.getOffset();
|
||||
}
|
||||
|
||||
public int addMetaspaceSymbol(String metaspaceName) {
|
||||
String gotName = "got." + metaspaceName;
|
||||
Symbol relocationSymbol = getGotSymbol(gotName);
|
||||
int metaspaceOffset = -1;
|
||||
if (relocationSymbol == null) {
|
||||
// Add slots when asked in the .metaspace.got section:
|
||||
metaspaceGotContainer.createGotSymbol(gotName);
|
||||
}
|
||||
return metaspaceOffset;
|
||||
}
|
||||
|
||||
public Symbol getGotSymbol(String name) {
|
||||
assert name.startsWith("got.");
|
||||
return symbolTable.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add metaspace symbol by as follows. - Adding the symbol name to the metaspace.names section -
|
||||
* Add the offset of the name in metaspace.names to metaspace.offsets - Extend the metaspace.got
|
||||
* section with another slot for the VM to patch
|
||||
*
|
||||
* @param metaspaceName name of the metaspace symbol
|
||||
* @return the got offset in the metaspace.got of the metaspace symbol
|
||||
*/
|
||||
public int addTwoSlotMetaspaceSymbol(String metaspaceName) {
|
||||
String gotName = "got." + metaspaceName;
|
||||
Symbol previous = getGotSymbol(gotName);
|
||||
assert previous == null : "should be called only once for: " + metaspaceName;
|
||||
// Add slots when asked in the .metaspace.got section:
|
||||
// First slot
|
||||
String gotInitName = "got.init." + metaspaceName;
|
||||
GotSymbol slot1Symbol = metaspaceGotContainer.createGotSymbol(gotInitName);
|
||||
GotSymbol slot2Symbol = metaspaceGotContainer.createGotSymbol(gotName);
|
||||
|
||||
slot1Symbol.getIndex(); // check alignment and ignore result
|
||||
// Get the index (offset/8) to the got in the .metaspace.got section
|
||||
return slot2Symbol.getIndex();
|
||||
}
|
||||
|
||||
public int addMethodsCount(int count, ReadOnlyDataContainer container) {
|
||||
return appendInt(count, container);
|
||||
}
|
||||
|
||||
private static int appendInt(int count, ReadOnlyDataContainer container) {
|
||||
int offset = container.getByteStreamSize();
|
||||
container.appendInt(count);
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add constant data as follows. - Adding the data to the method.constdata section
|
||||
*
|
||||
* @param data
|
||||
* @param alignment
|
||||
* @return the offset in the method.constdata of the data
|
||||
*/
|
||||
public int addConstantData(byte[] data, int alignment) {
|
||||
// Get the current length of the metaspaceNameContainer
|
||||
int constantDataOffset = alignUp(constantDataContainer, alignment);
|
||||
constantDataContainer.appendBytes(data, 0, data.length);
|
||||
alignUp(constantDataContainer, alignment); // Post alignment
|
||||
return constantDataOffset;
|
||||
}
|
||||
|
||||
public int alignUp(ByteContainer container, int alignment) {
|
||||
if (Integer.bitCount(alignment) != 1) {
|
||||
throw new IllegalArgumentException("Must be a power of 2");
|
||||
}
|
||||
int offset = container.getByteStreamSize();
|
||||
int aligned = (offset + (alignment - 1)) & -alignment;
|
||||
if (aligned < offset || (aligned & (alignment - 1)) != 0) {
|
||||
throw new RuntimeException("Error aligning: " + offset + " -> " + aligned);
|
||||
}
|
||||
if (aligned != offset) {
|
||||
int nullArraySz = aligned - offset;
|
||||
byte[] nullArray = new byte[nullArraySz];
|
||||
container.appendBytes(nullArray, 0, nullArraySz);
|
||||
offset = aligned;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void addCodeSegments(int start, int end) {
|
||||
assert (start % codeSegmentSize) == 0 : "not aligned code";
|
||||
int currentOffset = codeSegmentsContainer.getByteStreamSize();
|
||||
int offset = start / codeSegmentSize;
|
||||
int emptySize = offset - currentOffset;
|
||||
// add empty segments if needed
|
||||
if (emptySize > 0) {
|
||||
byte[] emptyArray = new byte[emptySize];
|
||||
for (int i = 0; i < emptySize; i++) {
|
||||
emptyArray[i] = (byte) 0xff;
|
||||
}
|
||||
appendBytes(codeSegmentsContainer, emptyArray, 0, emptySize);
|
||||
}
|
||||
int alignedEnd = (end + (codeSegmentSize - 1)) & -codeSegmentSize;
|
||||
int segmentsCount = (alignedEnd / codeSegmentSize) - offset;
|
||||
byte[] segments = new byte[segmentsCount];
|
||||
int idx = 0;
|
||||
for (int i = 0; i < segmentsCount; i++) {
|
||||
segments[i] = (byte) idx;
|
||||
idx = (idx == 0xfe) ? 1 : (idx + 1);
|
||||
}
|
||||
appendBytes(codeSegmentsContainer, segments, 0, segmentsCount);
|
||||
}
|
||||
|
||||
public CodeContainer getExtLinkageContainer() {
|
||||
return extLinkageContainer;
|
||||
}
|
||||
|
||||
public ByteContainer getExtLinkageGOTContainer() {
|
||||
return extLinkageGOTContainer;
|
||||
}
|
||||
|
||||
public ByteContainer getMethodMetadataContainer() {
|
||||
return methodMetadataContainer;
|
||||
}
|
||||
|
||||
public ReadOnlyDataContainer getMetaspaceNamesContainer() {
|
||||
return metaspaceNamesContainer;
|
||||
}
|
||||
|
||||
public ReadOnlyDataContainer getMethodsOffsetsContainer() {
|
||||
return methodsOffsetsContainer;
|
||||
}
|
||||
|
||||
public ReadOnlyDataContainer getKlassesOffsetsContainer() {
|
||||
return klassesOffsetsContainer;
|
||||
}
|
||||
|
||||
public ReadOnlyDataContainer getKlassesDependenciesContainer() {
|
||||
return klassesDependenciesContainer;
|
||||
}
|
||||
|
||||
public ReadOnlyDataContainer getStubsOffsetsContainer() {
|
||||
return stubsOffsetsContainer;
|
||||
}
|
||||
|
||||
public ReadOnlyDataContainer getCodeSegmentsContainer() {
|
||||
return codeSegmentsContainer;
|
||||
}
|
||||
|
||||
public ReadOnlyDataContainer getConstantDataContainer() {
|
||||
return constantDataContainer;
|
||||
}
|
||||
|
||||
public ByteContainer getMetaspaceGotContainer() {
|
||||
return metaspaceGotContainer;
|
||||
}
|
||||
|
||||
public ByteContainer getMetadataGotContainer() {
|
||||
return metadataGotContainer;
|
||||
}
|
||||
|
||||
public ByteContainer getMethodStateContainer() {
|
||||
return methodStateContainer;
|
||||
}
|
||||
|
||||
public ByteContainer getOopGotContainer() {
|
||||
return oopGotContainer;
|
||||
}
|
||||
|
||||
public CodeContainer getCodeContainer() {
|
||||
return codeContainer;
|
||||
}
|
||||
|
||||
public ReadOnlyDataContainer getConfigContainer() {
|
||||
return configContainer;
|
||||
}
|
||||
|
||||
public Map<Symbol, Relocation> getUniqueRelocationTable() {
|
||||
return uniqueRelocationTable;
|
||||
}
|
||||
|
||||
public HeaderContainer getHeaderContainer() {
|
||||
return headerContainer;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat;
|
||||
|
||||
import jdk.tools.jaotc.binformat.Symbol.Binding;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Kind;
|
||||
import jdk.tools.jaotc.jnilibelf.ELFContainer;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Base class that represents content of all sections with byte-level granularity. The ByteContainer
|
||||
* class is backed by a ByteArrayOutputStream. This class supports writing all desired byte content
|
||||
* to the container using the method {@code appendBytes} and accessing the byte array using the
|
||||
* method {@code getByteArray}.
|
||||
*
|
||||
* The method {@code putIntAt} updates the content of {@code contentBytes}. Changes are not
|
||||
* reflected in {@code contentStream}.
|
||||
*/
|
||||
public class ByteContainer implements ELFContainer {
|
||||
/**
|
||||
* {@code ByteBuffer} representation of {@code BinaryContainer}.
|
||||
*/
|
||||
private ByteBuffer contentBytes;
|
||||
|
||||
/**
|
||||
* {@code ByteArrayoutputStream} to which all appends are done.
|
||||
*/
|
||||
private ByteArrayOutputStream contentStream;
|
||||
|
||||
/**
|
||||
* Boolean to indicate if contentBytes was modified.
|
||||
*/
|
||||
private boolean bufferModified;
|
||||
|
||||
/**
|
||||
* Boolean to indicate if this section contains any relocations.
|
||||
*/
|
||||
private boolean hasRelocations;
|
||||
|
||||
/**
|
||||
* Name of this container, used as section name.
|
||||
*/
|
||||
private String containerName;
|
||||
private final SymbolTable symbolTable;
|
||||
|
||||
/**
|
||||
* Contains a unique id.
|
||||
*/
|
||||
private int sectionId = -1;
|
||||
|
||||
/**
|
||||
* Construct a {@code ByteContainer} object.
|
||||
*/
|
||||
public ByteContainer(String containerName, SymbolTable symbolTable) {
|
||||
this.containerName = containerName;
|
||||
this.symbolTable = symbolTable;
|
||||
this.contentBytes = null;
|
||||
this.bufferModified = false;
|
||||
this.hasRelocations = false;
|
||||
this.contentStream = new ByteArrayOutputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update byte buffer to reflect the current contents of byte stream.
|
||||
*
|
||||
* @throws InternalError throws {@code InternalError} if buffer byte array was modified
|
||||
*/
|
||||
private void updateByteBuffer() {
|
||||
if (!bufferModified) {
|
||||
contentBytes = ByteBuffer.wrap(contentStream.toByteArray());
|
||||
// Default byte order of ByteBuffer is BIG_ENDIAN.
|
||||
// Set it appropriately
|
||||
this.contentBytes.order(ByteOrder.nativeOrder());
|
||||
} else {
|
||||
throw new InternalError("Backing byte buffer no longer in sync with byte stream");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the byte array of {@code ByteContainer}.
|
||||
*
|
||||
* @return byte array
|
||||
* @throws InternalError throws {@code InternalError} if buffer byte array was modified
|
||||
*/
|
||||
public byte[] getByteArray() {
|
||||
if (!bufferModified) {
|
||||
updateByteBuffer();
|
||||
}
|
||||
return contentBytes.array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Append to byte stream. It is an error to append to stream if the byte buffer version is
|
||||
* changed.
|
||||
*
|
||||
* @param newBytes new content
|
||||
* @param off offset start offset in {@code newBytes}
|
||||
* @param len length of data to write
|
||||
* @throws InternalError throws {@code InternalError} if buffer byte array was modified
|
||||
*/
|
||||
public ByteContainer appendBytes(byte[] newBytes, int off, int len) {
|
||||
if (bufferModified) {
|
||||
throw new InternalError("Backing byte buffer no longer in sync with byte stream");
|
||||
}
|
||||
contentStream.write(newBytes, off, len);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ByteContainer appendBytes(byte[] newBytes) {
|
||||
appendBytes(newBytes, 0, newBytes.length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ByteContainer appendInt(int i) {
|
||||
if (bufferModified) {
|
||||
throw new InternalError("Backing byte buffer no longer in sync with byte stream");
|
||||
}
|
||||
ByteBuffer b = ByteBuffer.allocate(Integer.BYTES);
|
||||
b.order(ByteOrder.nativeOrder());
|
||||
b.putInt(i);
|
||||
byte[] result = b.array();
|
||||
contentStream.write(result, 0, result.length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ByteContainer appendInts(int[] newInts) {
|
||||
if (bufferModified) {
|
||||
throw new InternalError("Backing byte buffer no longer in sync with byte stream");
|
||||
}
|
||||
ByteBuffer b = ByteBuffer.allocate(Integer.BYTES * newInts.length).order(ByteOrder.nativeOrder());
|
||||
Arrays.stream(newInts).forEach(i -> b.putInt(i));
|
||||
byte[] result = b.array();
|
||||
contentStream.write(result, 0, result.length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void appendLong(long l) {
|
||||
if (bufferModified) {
|
||||
throw new InternalError("Backing byte buffer no longer in sync with byte stream");
|
||||
}
|
||||
ByteBuffer b = ByteBuffer.allocate(8);
|
||||
b.order(ByteOrder.nativeOrder());
|
||||
b.putLong(l);
|
||||
byte[] result = b.array();
|
||||
contentStream.write(result, 0, result.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current size of byte stream backing the BinaryContainer.
|
||||
*
|
||||
* @return size of buffer stream
|
||||
*/
|
||||
public int getByteStreamSize() {
|
||||
return contentStream.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of this container.
|
||||
*
|
||||
* @return string containing name
|
||||
*/
|
||||
public String getContainerName() {
|
||||
return containerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the byte buffer version of the byte output stream. Note that after calling this method
|
||||
* all further updates to BinaryContainer will be out of sync with byte buffer content.
|
||||
*
|
||||
* @param index index of byte to be changed
|
||||
* @param value new value
|
||||
*/
|
||||
public void putIntAt(int index, int value) {
|
||||
if (!bufferModified) {
|
||||
updateByteBuffer();
|
||||
}
|
||||
contentBytes.putInt(index, value);
|
||||
bufferModified = true;
|
||||
}
|
||||
|
||||
public void putLongAt(int index, long value) {
|
||||
if (!bufferModified) {
|
||||
updateByteBuffer();
|
||||
}
|
||||
contentBytes.putLong(index, value);
|
||||
bufferModified = true;
|
||||
}
|
||||
|
||||
public void setSectionId(int id) {
|
||||
if (sectionId != -1) {
|
||||
throw new InternalError("Assigning new sectionId (old: " + sectionId + ", new: " + id + ")");
|
||||
}
|
||||
sectionId = id;
|
||||
}
|
||||
|
||||
public int getSectionId() {
|
||||
if (sectionId == -1) {
|
||||
throw new InternalError("Using sectionId before assigned");
|
||||
}
|
||||
return sectionId;
|
||||
}
|
||||
|
||||
public Symbol createSymbol(int offset, Kind kind, Binding binding, int size, String name) {
|
||||
Symbol symbol = new Symbol(offset, kind, binding, this, size, name);
|
||||
symbolTable.addSymbol(symbol);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public GotSymbol createGotSymbol(String name) {
|
||||
GotSymbol symbol = new GotSymbol(Kind.OBJECT, Binding.LOCAL, this, name);
|
||||
symbolTable.addSymbol(symbol);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public GotSymbol createGotSymbol(int offset, String name) {
|
||||
GotSymbol symbol = new GotSymbol(offset, Kind.OBJECT, Binding.LOCAL, this, name);
|
||||
symbolTable.addSymbol(symbol);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.contentBytes = null;
|
||||
this.contentStream = null;
|
||||
}
|
||||
|
||||
public void setHasRelocations() {
|
||||
this.hasRelocations = true;
|
||||
}
|
||||
|
||||
public boolean hasRelocations() {
|
||||
return this.hasRelocations;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat;
|
||||
|
||||
/**
|
||||
* A container that holds information about code section. This is simply a ByteContainer.
|
||||
*/
|
||||
public class CodeContainer extends ByteContainer {
|
||||
|
||||
public CodeContainer(String containerName, SymbolTable symbolTable) {
|
||||
super(containerName, symbolTable);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat;
|
||||
|
||||
public class GotSymbol extends Symbol {
|
||||
|
||||
private static final int GOT_SIZE = 8;
|
||||
|
||||
public int getIndex() {
|
||||
int offset = getOffset();
|
||||
assert (offset % GOT_SIZE) == 0 : "got cells should be aligned: " + offset;
|
||||
return offset / GOT_SIZE;
|
||||
}
|
||||
|
||||
public GotSymbol(Kind type, Binding binding, ByteContainer container, String name) {
|
||||
this(container.getByteStreamSize(), type, binding, container, name);
|
||||
container.appendBytes(new byte[GOT_SIZE], 0, GOT_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create symbol info.
|
||||
*
|
||||
* @param offset section offset for the defined symbol
|
||||
* @param type type of the symbol (UNDEFINED, FUNC, etc)
|
||||
* @param binding binding of the symbol (LOCAL, GLOBAL, ...)
|
||||
* @param sec section in which this symbol is "defined"
|
||||
*/
|
||||
public GotSymbol(int offset, Kind type, Binding binding, ByteContainer sec, String name) {
|
||||
super(offset, type, binding, sec, GOT_SIZE, name);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class HeaderContainer {
|
||||
|
||||
private static final int CURRENT_VERSION = 1;
|
||||
private final ReadOnlyDataContainer container;
|
||||
// int _version;
|
||||
// int _class_count;
|
||||
// int _method_count;
|
||||
// int _metaspace_got_size;
|
||||
// int _metadata_got_size;
|
||||
// int _oop_got_size;
|
||||
// int _jvm_version_offset;
|
||||
|
||||
public HeaderContainer(String jvmVersion, ReadOnlyDataContainer container) {
|
||||
try {
|
||||
byte[] filler = new byte[4 * 7];
|
||||
container.appendBytes(filler);
|
||||
|
||||
// Store JVM version string at the end of header section.
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
DataOutputStream out = new DataOutputStream(bout);
|
||||
out.writeUTF(jvmVersion);
|
||||
out.writeShort(0); // Terminate by 0.
|
||||
byte[] b = bout.toByteArray();
|
||||
container.appendBytes(b, 0, b.length);
|
||||
} catch (IOException e) {
|
||||
throw new InternalError("Failed to append bytes to header section", e);
|
||||
}
|
||||
|
||||
this.container = container;
|
||||
this.container.putIntAt(0 * 4, CURRENT_VERSION);
|
||||
this.container.putIntAt(6 * 4, 7 * 4); // JVM version string offset
|
||||
}
|
||||
|
||||
public String getContainerName() {
|
||||
return container.getContainerName();
|
||||
}
|
||||
|
||||
public ReadOnlyDataContainer getContainer() {
|
||||
return container;
|
||||
}
|
||||
|
||||
public void setClassesCount(int count) {
|
||||
this.container.putIntAt(1 * 4, count);
|
||||
}
|
||||
|
||||
public void setMethodsCount(int count) {
|
||||
this.container.putIntAt(2 * 4, count);
|
||||
}
|
||||
|
||||
public void setMetaspaceGotSize(int size) {
|
||||
this.container.putIntAt(3 * 4, size);
|
||||
}
|
||||
|
||||
public void setMetadataGotSize(int size) {
|
||||
this.container.putIntAt(4 * 4, size);
|
||||
}
|
||||
|
||||
public void setOopGotSize(int size) {
|
||||
this.container.putIntAt(5 * 4, size);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat;
|
||||
|
||||
public class ReadOnlyDataContainer extends ByteContainer {
|
||||
|
||||
public ReadOnlyDataContainer(String containerName, SymbolTable symbolTable) {
|
||||
super(containerName, symbolTable);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat;
|
||||
|
||||
public class Relocation {
|
||||
|
||||
public enum RelocType {
|
||||
UNDEFINED,
|
||||
JAVA_CALL_INDIRECT,
|
||||
JAVA_CALL_DIRECT,
|
||||
FOREIGN_CALL_INDIRECT,
|
||||
FOREIGN_CALL_INDIRECT_GOT, // Call to address in GOT cell
|
||||
FOREIGN_CALL_DIRECT,
|
||||
FOREIGN_CALL_DIRECT_FAR,
|
||||
STUB_CALL_DIRECT,
|
||||
STUB_CALL_INDIRECT,
|
||||
EXTERNAL_DATA_REFERENCE_FAR,
|
||||
METASPACE_GOT_REFERENCE,
|
||||
EXTERNAL_GOT_TO_PLT,
|
||||
EXTERNAL_PLT_TO_GOT,
|
||||
STATIC_STUB_TO_STATIC_METHOD,
|
||||
STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT,
|
||||
LOADTIME_ADDRESS
|
||||
}
|
||||
|
||||
private final RelocType type;
|
||||
|
||||
/**
|
||||
* Byte offset from the beginning of the file affected by relocation.
|
||||
*/
|
||||
private final int offset;
|
||||
|
||||
/**
|
||||
* Size of relocation.
|
||||
*/
|
||||
private final int size;
|
||||
|
||||
/**
|
||||
* Symbol associated with this relocation.
|
||||
*/
|
||||
private final Symbol symbol;
|
||||
|
||||
/**
|
||||
* Section this relocation entry modifies.
|
||||
*/
|
||||
private final ByteContainer section;
|
||||
|
||||
public Relocation(int offset, RelocType type, int size, ByteContainer section, Symbol sym) {
|
||||
if (sym == null) {
|
||||
throw new InternalError("must have symbol");
|
||||
}
|
||||
this.offset = offset;
|
||||
this.type = type;
|
||||
this.size = size;
|
||||
this.symbol = sym;
|
||||
this.section = section;
|
||||
section.setHasRelocations();
|
||||
}
|
||||
|
||||
public RelocType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public Symbol getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public ByteContainer getSection() {
|
||||
return section;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.tools.jaotc.jnilibelf.ELFSymbol;
|
||||
|
||||
public class Symbol {
|
||||
|
||||
public enum Binding {
|
||||
UNDEFINED,
|
||||
LOCAL,
|
||||
GLOBAL
|
||||
}
|
||||
|
||||
public enum Kind {
|
||||
UNDEFINED,
|
||||
NATIVE_FUNCTION,
|
||||
JAVA_FUNCTION,
|
||||
STATIC_STUB_CALL, // static call stub inside the text section
|
||||
OBJECT,
|
||||
NOTYPE
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final int size;
|
||||
private final int offset;
|
||||
private final Binding binding;
|
||||
private final Kind kind;
|
||||
|
||||
private ByteContainer section;
|
||||
private ELFSymbol elfSymbol;
|
||||
|
||||
/**
|
||||
* Create symbol info.
|
||||
*
|
||||
* @param offset section offset for the defined symbol
|
||||
* @param kind kind of the symbol (UNDEFINED, FUNC, etc)
|
||||
* @param binding binding of the symbol (LOCAL, GLOBAL, ...)
|
||||
* @param section section in which this symbol is "defined"
|
||||
* @param size size of the symbol
|
||||
* @param name name of the symbol
|
||||
*/
|
||||
|
||||
public Symbol(int offset, Kind kind, Binding binding, ByteContainer section, int size, String name) {
|
||||
this.binding = binding;
|
||||
this.kind = kind;
|
||||
this.section = section;
|
||||
this.size = size;
|
||||
this.offset = offset;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ELFSymbol getElfSymbol() {
|
||||
return elfSymbol;
|
||||
}
|
||||
|
||||
public void setElfSymbol(ELFSymbol elfSymbol) {
|
||||
this.elfSymbol = elfSymbol;
|
||||
}
|
||||
|
||||
public Binding getBinding() {
|
||||
return binding;
|
||||
}
|
||||
|
||||
public Kind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public ByteContainer getSection() {
|
||||
return section;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Symbol)) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Symbol symbol = (Symbol) obj;
|
||||
|
||||
if (size != symbol.size) {
|
||||
return false;
|
||||
}
|
||||
if (offset != symbol.offset) {
|
||||
return false;
|
||||
}
|
||||
if (!name.equals(symbol.name)) {
|
||||
return false;
|
||||
}
|
||||
if (binding != symbol.binding) {
|
||||
return false;
|
||||
}
|
||||
if (kind != symbol.kind) {
|
||||
return false;
|
||||
}
|
||||
return !(section != null ? !section.equals(symbol.section) : symbol.section != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(name, binding, kind, section);
|
||||
result = 31 * result + size;
|
||||
result = 31 * result + offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + name + ", " + size + ", " + offset + ", " + binding + ", " + kind + ", " + section + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat;
|
||||
|
||||
public interface SymbolTable {
|
||||
void addSymbol(Symbol symInfo);
|
||||
|
||||
Symbol getSymbol(String symName);
|
||||
|
||||
Symbol createSymbol(int offset, Symbol.Kind kind, Symbol.Binding binding, int size, String name);
|
||||
}
|
||||
@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.elf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.tools.jaotc.binformat.BinaryContainer;
|
||||
import jdk.tools.jaotc.binformat.ByteContainer;
|
||||
import jdk.tools.jaotc.binformat.CodeContainer;
|
||||
import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
|
||||
import jdk.tools.jaotc.binformat.Relocation;
|
||||
import jdk.tools.jaotc.binformat.Relocation.RelocType;
|
||||
import jdk.tools.jaotc.binformat.Symbol;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Binding;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Kind;
|
||||
import jdk.tools.jaotc.jnilibelf.ELFContainer;
|
||||
import jdk.tools.jaotc.jnilibelf.ELFSymbol;
|
||||
import jdk.tools.jaotc.jnilibelf.JNIELFContainer;
|
||||
import jdk.tools.jaotc.jnilibelf.JNIELFRelocation;
|
||||
import jdk.tools.jaotc.jnilibelf.JNIELFTargetInfo;
|
||||
import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.ELF;
|
||||
import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Cmd;
|
||||
import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Type;
|
||||
import jdk.tools.jaotc.jnilibelf.Pointer;
|
||||
|
||||
public class JELFRelocObject {
|
||||
|
||||
private final BinaryContainer binContainer;
|
||||
|
||||
private final JNIELFContainer elfContainer;
|
||||
|
||||
private final int segmentSize;
|
||||
|
||||
public JELFRelocObject(BinaryContainer binContainer, String outputFileName, String aotVersion) {
|
||||
this.binContainer = binContainer;
|
||||
this.elfContainer = new JNIELFContainer(outputFileName, aotVersion);
|
||||
this.segmentSize = binContainer.getCodeSegmentSize();
|
||||
}
|
||||
|
||||
private void createByteSection(ByteContainer c, int scnFlags) {
|
||||
byte[] scnData = c.getByteArray();
|
||||
int scnType = ELF.SHT_PROGBITS;
|
||||
boolean zeros = !c.hasRelocations();
|
||||
if (zeros) {
|
||||
for (byte b : scnData) {
|
||||
if (b != 0) {
|
||||
zeros = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (zeros) {
|
||||
scnType = ELF.SHT_NOBITS;
|
||||
}
|
||||
}
|
||||
|
||||
int sectionId = elfContainer.createSection(c.getContainerName(), scnData, Elf_Type.ELF_T_BYTE, segmentSize, scnType, scnFlags, ELF.SHN_UNDEF, 0);
|
||||
c.setSectionId(sectionId);
|
||||
// Clear out code section data to allow for GC
|
||||
c.clear();
|
||||
}
|
||||
|
||||
private void createCodeSection(CodeContainer c) {
|
||||
createByteSection(c, ELF.SHF_ALLOC | ELF.SHF_EXECINSTR);
|
||||
}
|
||||
|
||||
private void createReadOnlySection(ReadOnlyDataContainer c) {
|
||||
createByteSection(c, ELF.SHF_ALLOC);
|
||||
}
|
||||
|
||||
private void createReadWriteSection(ByteContainer c) {
|
||||
createByteSection(c, ELF.SHF_ALLOC | ELF.SHF_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ELF relocatable object using jdk.tools.jaotc.jnilibelf API.
|
||||
*
|
||||
* @param relocationTable
|
||||
* @param symbols
|
||||
* @throws IOException throws {@code IOException} as a result of file system access failures.
|
||||
*/
|
||||
public void createELFRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException {
|
||||
// Allocate ELF Header
|
||||
elfContainer.createELFHeader(ELF.ET_REL);
|
||||
|
||||
// Create text section
|
||||
createCodeSection(binContainer.getCodeContainer());
|
||||
createReadOnlySection(binContainer.getMetaspaceNamesContainer());
|
||||
createReadOnlySection(binContainer.getKlassesOffsetsContainer());
|
||||
createReadOnlySection(binContainer.getMethodsOffsetsContainer());
|
||||
createReadOnlySection(binContainer.getKlassesDependenciesContainer());
|
||||
createReadWriteSection(binContainer.getMetaspaceGotContainer());
|
||||
createReadWriteSection(binContainer.getMetadataGotContainer());
|
||||
createReadWriteSection(binContainer.getMethodStateContainer());
|
||||
createReadWriteSection(binContainer.getOopGotContainer());
|
||||
createReadWriteSection(binContainer.getMethodMetadataContainer());
|
||||
createReadOnlySection(binContainer.getStubsOffsetsContainer());
|
||||
createReadOnlySection(binContainer.getHeaderContainer().getContainer());
|
||||
createReadOnlySection(binContainer.getCodeSegmentsContainer());
|
||||
createReadOnlySection(binContainer.getConstantDataContainer());
|
||||
createReadOnlySection(binContainer.getConfigContainer());
|
||||
|
||||
// createExternalLinkage();
|
||||
|
||||
createCodeSection(binContainer.getExtLinkageContainer());
|
||||
createReadWriteSection(binContainer.getExtLinkageGOTContainer());
|
||||
|
||||
// Get ELF symbol data from BinaryContainer object's symbol tables
|
||||
createELFSymbolTables(symbols);
|
||||
|
||||
// Create string table section and symbol table sections in
|
||||
// that order since symtab section needs to set the index of strtab in sh_link field
|
||||
int strTabSectionIndex = elfContainer.createSection(".strtab", elfContainer.getStrTabContent().getBytes(StandardCharsets.UTF_8), Elf_Type.ELF_T_BYTE, 1, ELF.SHT_STRTAB, 0, ELF.SHN_UNDEF, 0);
|
||||
|
||||
// Now create .symtab section with the symtab data constructed. On Linux, sh_link of symtab
|
||||
// contains the index of string table its symbols reference and
|
||||
// sh_info contains the index of first non-local symbol
|
||||
int scnInfo = elfContainer.getFirstNonLocalSymbolIndex();
|
||||
int symTabSectionIndex = elfContainer.createSection(".symtab", getELFSymbolTableData(), Elf_Type.ELF_T_SYM, 8, ELF.SHT_SYMTAB, ELF.SHF_ALLOC, strTabSectionIndex, scnInfo);
|
||||
|
||||
buildRelocations(relocationTable, symTabSectionIndex);
|
||||
|
||||
// Now, finally, after creating all sections, create shstrtab section
|
||||
elfContainer.createSection(".shstrtab", elfContainer.getShStrTabContent().getBytes(StandardCharsets.UTF_8), Elf_Type.ELF_T_BYTE, 1, ELF.SHT_STRTAB, 0, ELF.SHN_UNDEF, 0);
|
||||
|
||||
// Run elf_update
|
||||
elfContainer.elfUpdate(Elf_Cmd.ELF_C_NULL);
|
||||
|
||||
// Run elfUpdate again to write it out.
|
||||
elfContainer.elfUpdate(Elf_Cmd.ELF_C_WRITE);
|
||||
// Finish ELF processing
|
||||
elfContainer.elfEnd();
|
||||
}
|
||||
|
||||
private void buildRelocations(Map<Symbol, List<Relocation>> relocationTable, final int symTabSectionIndex) {
|
||||
/*
|
||||
* Create relocation sections. This needs to be done after symbol table sections were
|
||||
* created since relocation entries will need indices of sections to which they apply.
|
||||
*/
|
||||
createELFRelocationTables(relocationTable);
|
||||
createAllRelocationSections(new SymTabELFContainer(symTabSectionIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct ELF symbol data from BinaryContainer object's symbol tables. Both dynamic ELF
|
||||
* symbol table and ELF symbol table are created from BinaryContainer's symbol info.
|
||||
*
|
||||
* @param symbols
|
||||
*/
|
||||
private void createELFSymbolTables(Collection<Symbol> symbols) {
|
||||
// First, create the initial null symbol. This is a local symbol.
|
||||
elfContainer.createELFSymbolEntry("", 0, 0, ELF.SHN_UNDEF, 0, 0, true);
|
||||
|
||||
// Now create ELF symbol entries for all symbols.
|
||||
for (Symbol symbol : symbols) {
|
||||
// Get the index of section this symbol is defined in.
|
||||
int secHdrIndex = symbol.getSection().getSectionId();
|
||||
boolean isLocal = (symbol.getBinding() == Binding.LOCAL);
|
||||
ELFSymbol elfSymbol = elfContainer.createELFSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), secHdrIndex, symbol.getSize(), symbol.getOffset(), isLocal);
|
||||
symbol.setElfSymbol(elfSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct ELF symbol data from BinaryContainer object's symbol tables.
|
||||
*
|
||||
* @return a byte array containing the symbol table
|
||||
*/
|
||||
private byte[] getELFSymbolTableData() {
|
||||
final int entrySize = JNIELFTargetInfo.sizeOfSymtabEntry();
|
||||
|
||||
// First, add all local symbols.
|
||||
List<ELFSymbol> localSymbols = elfContainer.getLocalSymbols();
|
||||
List<ELFSymbol> globalSymbols = elfContainer.getGlobalSymbols();
|
||||
|
||||
int localSymCount = localSymbols.size();
|
||||
int globalSymCount = globalSymbols.size();
|
||||
byte[] sectionDataArray = new byte[(localSymCount + globalSymCount) * entrySize];
|
||||
|
||||
for (int i = 0; i < localSymCount; i++) {
|
||||
ELFSymbol symbol = localSymbols.get(i);
|
||||
Pointer address = symbol.getAddress();
|
||||
address.copyBytesTo(sectionDataArray, entrySize, i * entrySize);
|
||||
}
|
||||
|
||||
// Next, add all global symbols.
|
||||
|
||||
for (int i = 0; i < globalSymCount; i++) {
|
||||
ELFSymbol symbol = globalSymbols.get(i);
|
||||
Pointer address = symbol.getAddress();
|
||||
address.copyBytesTo(sectionDataArray, entrySize, (localSymCount + i) * entrySize);
|
||||
}
|
||||
|
||||
return sectionDataArray;
|
||||
}
|
||||
|
||||
private static int getELFTypeOf(Symbol sym) {
|
||||
Kind kind = sym.getKind();
|
||||
if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) {
|
||||
return ELF.STT_FUNC;
|
||||
} else if (kind == Symbol.Kind.OBJECT) {
|
||||
return ELF.STT_OBJECT;
|
||||
}
|
||||
return ELF.STT_NOTYPE;
|
||||
}
|
||||
|
||||
private static int getELFBindOf(Symbol sym) {
|
||||
Binding binding = sym.getBinding();
|
||||
if (binding == Symbol.Binding.GLOBAL) {
|
||||
return ELF.STB_GLOBAL;
|
||||
}
|
||||
return ELF.STB_LOCAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct ELF relocation section data from BinaryContainer object's relocation tables.
|
||||
*
|
||||
* @param relocationTable
|
||||
*/
|
||||
private void createELFRelocationTables(Map<Symbol, List<Relocation>> relocationTable) {
|
||||
/*
|
||||
* For each of the symbols with associated relocation records, create an ELF relocation
|
||||
* entry.
|
||||
*/
|
||||
for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
|
||||
List<Relocation> relocs = entry.getValue();
|
||||
Symbol symbol = entry.getKey();
|
||||
|
||||
for (Relocation reloc : relocs) {
|
||||
createRelocation(symbol, reloc);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) {
|
||||
createRelocation(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void createRelocation(Symbol symbol, Relocation reloc) {
|
||||
RelocType relocType = reloc.getType();
|
||||
int elfRelocType = getELFRelocationType(relocType);
|
||||
|
||||
switch (relocType) {
|
||||
case FOREIGN_CALL_DIRECT:
|
||||
case JAVA_CALL_DIRECT:
|
||||
case STUB_CALL_DIRECT:
|
||||
case FOREIGN_CALL_INDIRECT_GOT: {
|
||||
// Create relocation entry
|
||||
int addend = -4; // Size in bytes of the patch location
|
||||
// Relocation should be applied at the location after call operand
|
||||
int offset = reloc.getOffset() + reloc.getSize() + addend;
|
||||
elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
|
||||
break;
|
||||
}
|
||||
case FOREIGN_CALL_DIRECT_FAR: {
|
||||
// Create relocation entry
|
||||
int addend = -8; // Size in bytes of the patch location
|
||||
// Relocation should be applied at the location after call operand
|
||||
// 10 = 2 (jmp [r]) + 8 (imm64)
|
||||
int offset = reloc.getOffset() + reloc.getSize() + addend - 2;
|
||||
elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
|
||||
break;
|
||||
}
|
||||
case FOREIGN_CALL_INDIRECT:
|
||||
case JAVA_CALL_INDIRECT:
|
||||
case STUB_CALL_INDIRECT: {
|
||||
// Do nothing.
|
||||
break;
|
||||
}
|
||||
case EXTERNAL_DATA_REFERENCE_FAR: {
|
||||
// Create relocation entry
|
||||
int addend = -4; // Size of 32-bit address of the GOT
|
||||
/*
|
||||
* Relocation should be applied before the test instruction to the move instruction.
|
||||
* reloc.getOffset() points to the test instruction after the instruction that loads
|
||||
* the address of polling page. So set the offset appropriately.
|
||||
*/
|
||||
int offset = reloc.getOffset() + addend;
|
||||
elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
|
||||
break;
|
||||
}
|
||||
case METASPACE_GOT_REFERENCE:
|
||||
case EXTERNAL_PLT_TO_GOT:
|
||||
case STATIC_STUB_TO_STATIC_METHOD:
|
||||
case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: {
|
||||
int addend = -4; // Size of 32-bit address of the GOT
|
||||
/*
|
||||
* Relocation should be applied before the test instruction to the move instruction.
|
||||
* reloc.getOffset() points to the test instruction after the instruction that loads
|
||||
* the address of polling page. So set the offset appropriately.
|
||||
*/
|
||||
int offset = reloc.getOffset() + addend;
|
||||
elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
|
||||
break;
|
||||
}
|
||||
case EXTERNAL_GOT_TO_PLT:
|
||||
case LOADTIME_ADDRESS: {
|
||||
// this is load time relocations
|
||||
elfContainer.createELFRelocationEntry(reloc.getSection(), reloc.getOffset(), elfRelocType, 0, symbol.getElfSymbol());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InternalError("Unhandled relocation type: " + relocType);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Populate the mapping of RelocType to ELF relocation types
|
||||
private static int getELFRelocationType(RelocType relocType) {
|
||||
int elfRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH
|
||||
switch (JNIELFTargetInfo.getELFArch()) {
|
||||
case ELF.EM_X64_64:
|
||||
// Return R_X86_64_* entries based on relocType
|
||||
if (relocType == RelocType.FOREIGN_CALL_DIRECT || relocType == RelocType.JAVA_CALL_DIRECT || relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PLT32;
|
||||
} else if (relocType == RelocType.STUB_CALL_DIRECT) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PC32;
|
||||
} else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_64;
|
||||
} else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || relocType == RelocType.JAVA_CALL_INDIRECT || relocType == RelocType.STUB_CALL_INDIRECT) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_NONE;
|
||||
} else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_GOTPCREL;
|
||||
} else if (relocType == RelocType.METASPACE_GOT_REFERENCE || relocType == RelocType.EXTERNAL_PLT_TO_GOT || relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD ||
|
||||
relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PC32;
|
||||
} else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || relocType == RelocType.LOADTIME_ADDRESS) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_64;
|
||||
} else {
|
||||
assert false : "Unhandled relocation type: " + relocType;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
System.out.println("Relocation Type mapping: Unhandled architecture");
|
||||
}
|
||||
return elfRelocType;
|
||||
}
|
||||
|
||||
private void createAllRelocationSections(ELFContainer symtab) {
|
||||
for (Map.Entry<ELFContainer, ArrayList<Pointer>> entry : elfContainer.getRelocTables().entrySet()) {
|
||||
createRelocationSection(entry.getKey(), entry.getValue(), symtab);
|
||||
}
|
||||
}
|
||||
|
||||
private void createRelocationSection(ELFContainer container, ArrayList<Pointer> relocations, ELFContainer symtab) {
|
||||
String secName = container.getContainerName();
|
||||
int entrySize = JNIELFTargetInfo.sizeOfRelocEntry();
|
||||
int numEntries = relocations.size();
|
||||
byte[] sectionDataBytes = new byte[numEntries * entrySize];
|
||||
|
||||
for (int index = 0; index < relocations.size(); index++) {
|
||||
Pointer entry = relocations.get(index);
|
||||
entry.copyBytesTo(sectionDataBytes, entrySize, index * entrySize);
|
||||
}
|
||||
String fullSecName;
|
||||
// If relocDat is non-null create section
|
||||
if (sectionDataBytes.length > 0) {
|
||||
int scnType;
|
||||
Elf_Type dataType;
|
||||
if (JNIELFTargetInfo.createReloca() == 0) {
|
||||
scnType = ELF.SHT_REL;
|
||||
dataType = Elf_Type.ELF_T_REL;
|
||||
fullSecName = ".rel" + secName;
|
||||
} else {
|
||||
scnType = ELF.SHT_RELA;
|
||||
dataType = Elf_Type.ELF_T_RELA;
|
||||
fullSecName = ".rela" + secName;
|
||||
}
|
||||
// assert compareBytes(relocData.toByteArray(), sectionDataBytes) : "******* Bad array
|
||||
// copy";
|
||||
// sh_link holds the index of section header of symbol table associated with this
|
||||
// relocation table.
|
||||
// sh_info holds the index of section header to which this relocation table applies
|
||||
// to.
|
||||
elfContainer.createSection(fullSecName, sectionDataBytes, dataType, 8, scnType, ELF.SHF_ALLOC, symtab.getSectionId(), container.getSectionId());
|
||||
}
|
||||
}
|
||||
|
||||
private static class SymTabELFContainer implements ELFContainer {
|
||||
private final int symTabSectionIndex;
|
||||
|
||||
public SymTabELFContainer(int symTabSectionIndex) {
|
||||
this.symTabSectionIndex = symTabSectionIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContainerName() {
|
||||
return ".symtab";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionId() {
|
||||
return symTabSectionIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.jnilibelf;
|
||||
|
||||
public interface ELFContainer {
|
||||
|
||||
String getContainerName();
|
||||
|
||||
int getSectionId();
|
||||
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.jnilibelf;
|
||||
|
||||
/**
|
||||
* This class represents a {@code Elf32_Sym} or {@code Elf64_Sym} as defined in {@code elf.h}.
|
||||
*/
|
||||
public class ELFSymbol {
|
||||
/** Symbol name. */
|
||||
private final String name;
|
||||
|
||||
/** String table index. */
|
||||
private final int index;
|
||||
|
||||
/** Native memory address of ELF sym entry. */
|
||||
private final Pointer address;
|
||||
private final boolean isLocal;
|
||||
|
||||
public ELFSymbol(String name, int index, Pointer address, boolean isLocal) {
|
||||
this.name = name;
|
||||
this.index = index;
|
||||
this.address = address;
|
||||
this.isLocal = isLocal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the index
|
||||
*/
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the address
|
||||
*/
|
||||
public Pointer getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "name=" + name + ", index=" + index + ", address=" + address;
|
||||
}
|
||||
|
||||
public boolean isLocal() {
|
||||
return isLocal;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,476 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.jnilibelf;
|
||||
|
||||
import static jdk.tools.jaotc.jnilibelf.UnsafeAccess.UNSAFE;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.ELF;
|
||||
import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF;
|
||||
import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Type;
|
||||
|
||||
/**
|
||||
* A class abstraction of an ELF file.
|
||||
*
|
||||
*/
|
||||
public class JNIELFContainer {
|
||||
|
||||
private String outputFileName;
|
||||
private File outFile;
|
||||
private int outFileDesc;
|
||||
|
||||
/**
|
||||
* Pointer to Elf file. This is the same as struct Elf found in libelf.h
|
||||
*/
|
||||
private Pointer elfPtr;
|
||||
|
||||
/**
|
||||
* Class of the ELF container - one of ELFCLASS32 or ELFCLASS64.
|
||||
*/
|
||||
private final int elfClass;
|
||||
|
||||
/**
|
||||
* Pointer to ELF Header.
|
||||
*/
|
||||
private Pointer ehdrPtr;
|
||||
|
||||
/**
|
||||
* Pointer to Program Header.
|
||||
*/
|
||||
private Pointer phdrPtr;
|
||||
|
||||
/**
|
||||
* String holding .shstrtab contents.
|
||||
*/
|
||||
private String shStrTabContent = "";
|
||||
|
||||
/**
|
||||
* Map of local symbol indexes to ELF symbol entries.
|
||||
*/
|
||||
private List<ELFSymbol> localSymbolIndex = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Map of global symbol indexes to ELF symbol entries.
|
||||
*/
|
||||
private List<ELFSymbol> globalSymbolIndex = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* String holding .strtab contents.
|
||||
*/
|
||||
private StringBuilder strTabContent = new StringBuilder();
|
||||
|
||||
/**
|
||||
* Keeps track of nr of bytes in .strtab since strTabContent.length() is number of chars, not
|
||||
* bytes.
|
||||
*/
|
||||
private int strTabNrOfBytes = 0;
|
||||
|
||||
/**
|
||||
* A hashtable that holds (section-name, relocation-table) pairs. For example, [(".rela.text",
|
||||
* rela-text-reloc-entries), (".rela.plt", rela-plt-reloc-entries), ...].
|
||||
*/
|
||||
private Map<ELFContainer, ArrayList<Pointer>> relocTables = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Create reloca; 0 => false and non-zero => true.
|
||||
*/
|
||||
private final int createReloca;
|
||||
|
||||
/**
|
||||
* Construct an ELFContainer in preparation for a disk image with file {@code prefix}.
|
||||
*
|
||||
* @param fileName name of ELF file to be created
|
||||
*/
|
||||
public JNIELFContainer(String fileName, String aotVersion) {
|
||||
// Check for version compatibility
|
||||
if (!JNILibELFAPI.elfshim_version().equals(aotVersion)) {
|
||||
throw new InternalError("libelfshim version mismatch: " + JNILibELFAPI.elfshim_version() + " vs " + aotVersion);
|
||||
}
|
||||
|
||||
elfClass = JNIELFTargetInfo.getELFClass();
|
||||
createReloca = JNIELFTargetInfo.createReloca();
|
||||
outputFileName = fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local ELF symbol table.
|
||||
*
|
||||
* @return local symbol table
|
||||
*/
|
||||
public List<ELFSymbol> getLocalSymbols() {
|
||||
return localSymbolIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the global ELF symbol table.
|
||||
*
|
||||
* @return list of global ELF symbol table entries
|
||||
*/
|
||||
public List<ELFSymbol> getGlobalSymbols() {
|
||||
return globalSymbolIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string table content (.strtab).
|
||||
*
|
||||
* @return string table content
|
||||
*/
|
||||
public String getStrTabContent() {
|
||||
return strTabContent.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get section header string table content (.shstrtab).
|
||||
*
|
||||
* @return section header string table content
|
||||
*/
|
||||
public String getShStrTabContent() {
|
||||
return shStrTabContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get relocation tables.
|
||||
*
|
||||
* @return relocation tables
|
||||
*/
|
||||
public Map<ELFContainer, ArrayList<Pointer>> getRelocTables() {
|
||||
return relocTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of first non-local symbol in symbol table.
|
||||
*
|
||||
* @return symbol table index
|
||||
*/
|
||||
public int getFirstNonLocalSymbolIndex() {
|
||||
return localSymbolIndex.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create ELF header of type {@code ececType}.
|
||||
*
|
||||
* @param type type of ELF executable
|
||||
*/
|
||||
public void createELFHeader(int type) {
|
||||
// Check for version compatibility
|
||||
if (JNILibELFAPI.elf_version(ELF.EV_CURRENT) == ELF.EV_NONE) {
|
||||
throw new InternalError("ELF version mismatch");
|
||||
}
|
||||
|
||||
outFile = constructRelocFile(outputFileName);
|
||||
// Open a temporary file for the shared library to be created
|
||||
// TODO: Revisit file permissions; need to add execute permission
|
||||
outFileDesc = JNILibELFAPI.open_rw(outFile.getPath());
|
||||
|
||||
if (outFileDesc == -1) {
|
||||
System.out.println("Failed to open file " + outFile.getPath() + " to write relocatable object.");
|
||||
}
|
||||
|
||||
elfPtr = JNILibELFAPI.elf_begin(outFileDesc, LibELF.Elf_Cmd.ELF_C_WRITE.intValue(), new Pointer(0L));
|
||||
if (elfPtr == null) {
|
||||
throw new InternalError("elf_begin failed");
|
||||
}
|
||||
|
||||
// Allocate new Ehdr of current architecture class
|
||||
|
||||
ehdrPtr = JNILibELFAPI.gelf_newehdr(elfPtr, elfClass);
|
||||
|
||||
JNILibELFAPI.ehdr_set_data_encoding(ehdrPtr, JNIELFTargetInfo.getELFEndian());
|
||||
JNILibELFAPI.set_Ehdr_e_machine(elfClass, ehdrPtr, JNIELFTargetInfo.getELFArch());
|
||||
JNILibELFAPI.set_Ehdr_e_type(elfClass, ehdrPtr, type);
|
||||
JNILibELFAPI.set_Ehdr_e_version(elfClass, ehdrPtr, ELF.EV_CURRENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the file name has a .so extension, replace it with .o extension. Else just add .o
|
||||
* extension
|
||||
*
|
||||
* @param fileName
|
||||
* @return File object
|
||||
*/
|
||||
private static File constructRelocFile(String fileName) {
|
||||
File relocFile = new File(fileName);
|
||||
if (relocFile.exists()) {
|
||||
if (!relocFile.delete()) {
|
||||
throw new InternalError("Failed to delete existing " + fileName + " file");
|
||||
}
|
||||
}
|
||||
return relocFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@code count} number of Program headers.
|
||||
*
|
||||
* @param count number of program headers to create
|
||||
* @return true upon success; false upon failure
|
||||
*/
|
||||
public boolean createProgramHeader(int count) {
|
||||
phdrPtr = JNILibELFAPI.gelf_newphdr(elfPtr, count);
|
||||
if (phdrPtr == null) {
|
||||
System.out.println("gelf_newphdr error");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set program header to be of type self.
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public boolean setProgHdrTypeToSelf() {
|
||||
// Set program header to be of type self
|
||||
JNILibELFAPI.phdr_set_type_self(elfClass, ehdrPtr, phdrPtr);
|
||||
// And thus mark it as dirty so that elfUpdate can recompute the structures
|
||||
JNILibELFAPI.elf_flagphdr(elfPtr, LibELF.Elf_Cmd.ELF_C_SET.intValue(), LibELF.ELF_F_DIRTY);
|
||||
// TODO: Error checking; look at the return value of elf_update
|
||||
// and call elf_errmsg appropriately.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a section. The corresponding section header and section data are created by calling
|
||||
* the necessary libelf APIs. The section that is created is inserted into the ELF container.
|
||||
*
|
||||
* @param secName name of the section
|
||||
* @param scnData section data
|
||||
* @param dataType data type
|
||||
* @param align section alignment
|
||||
* @param scnType section type
|
||||
* @param scnFlags section flags
|
||||
* @param scnLink sh_link field of Elf{32,64}_Shdr
|
||||
* @param scnInfo sh_info field of Elf{32,64}_Shdr
|
||||
* @return section index
|
||||
*/
|
||||
public int createSection(String secName, byte[] scnData, Elf_Type dataType, int align, int scnType, int scnFlags, int scnLink, int scnInfo) {
|
||||
// Create a new section
|
||||
Pointer scnPtr = JNILibELFAPI.elf_newscn(elfPtr);
|
||||
if (scnPtr == null) {
|
||||
throw new InternalError("elf_newscn error");
|
||||
}
|
||||
|
||||
// Allocate section data for the section
|
||||
Pointer scnDataPtr = JNILibELFAPI.elf_newdata(scnPtr);
|
||||
if (scnDataPtr == null) {
|
||||
String errMsg = JNILibELFAPI.elf_errmsg(-1);
|
||||
throw new InternalError("elf_newdata error: " + errMsg);
|
||||
}
|
||||
|
||||
// Get the pointer to section header associated with the new section
|
||||
Pointer scnHdrPtr = JNILibELFAPI.elf64_getshdr(scnPtr);
|
||||
|
||||
// Add name of the section to section name string
|
||||
// If secName is null, point the name to the 0th index
|
||||
// that holds `\0'
|
||||
byte[] modScnData;
|
||||
if (secName.isEmpty()) {
|
||||
JNILibELFAPI.set_Shdr_sh_name(elfClass, scnHdrPtr, 0);
|
||||
modScnData = scnData;
|
||||
} else {
|
||||
if (secName.equals(".shstrtab")) {
|
||||
// Modify .shstrtab data by inserting '\0' at index 0
|
||||
String shstrtabSecName = ".shstrtab" + '\0';
|
||||
// Additional byte for the '\0' at position 0
|
||||
ByteBuffer nbuf = ByteBuffer.allocate(scnData.length + 1 + shstrtabSecName.length());
|
||||
nbuf.put(0, (byte) 0);
|
||||
nbuf.position(1);
|
||||
nbuf.put(scnData);
|
||||
nbuf.position(scnData.length + 1);
|
||||
// Add the section name ".shstrtab" to its own data
|
||||
nbuf.put(shstrtabSecName.getBytes(StandardCharsets.UTF_8));
|
||||
modScnData = nbuf.array();
|
||||
JNILibELFAPI.set_Shdr_sh_name(elfClass, scnHdrPtr, scnData.length + 1);
|
||||
// Set strtab section index
|
||||
JNILibELFAPI.set_Ehdr_e_shstrndx(elfClass, ehdrPtr, JNILibELFAPI.elf_ndxscn(scnPtr));
|
||||
} else if (secName.equals(".strtab")) {
|
||||
// Modify strtab section data to insert '\0' at position 0.
|
||||
// Additional byte for the '\0' at position 0
|
||||
ByteBuffer nbuf = ByteBuffer.allocate(scnData.length + 1);
|
||||
nbuf.put(0, (byte) 0);
|
||||
nbuf.position(1);
|
||||
nbuf.put(scnData);
|
||||
modScnData = nbuf.array();
|
||||
// Set the sh_name
|
||||
JNILibELFAPI.set_Shdr_sh_name(elfClass, scnHdrPtr, shStrTabContent.length() + 1);
|
||||
// Add scnName to stringList
|
||||
shStrTabContent += secName + '\0';
|
||||
} else {
|
||||
// Set the sh_name
|
||||
JNILibELFAPI.set_Shdr_sh_name(elfClass, scnHdrPtr, shStrTabContent.length() + 1);
|
||||
// Add scnName to stringList
|
||||
shStrTabContent += secName + '\0';
|
||||
modScnData = scnData;
|
||||
}
|
||||
}
|
||||
|
||||
final int scnDataBufSize = modScnData.length;
|
||||
|
||||
Pointer scnDataBufPtr = null;
|
||||
if (scnType != ELF.SHT_NOBITS) {
|
||||
// Allocate native memory for section data
|
||||
final long address = UNSAFE.allocateMemory(scnDataBufSize + 1);
|
||||
scnDataBufPtr = new Pointer(address);
|
||||
scnDataBufPtr.put(modScnData);
|
||||
} else {
|
||||
scnDataBufPtr = new Pointer(0L);
|
||||
}
|
||||
|
||||
// Set data descriptor fields
|
||||
JNILibELFAPI.set_Data_d_align(scnDataPtr, align);
|
||||
JNILibELFAPI.set_Data_d_buf(scnDataPtr, scnDataBufPtr);
|
||||
JNILibELFAPI.set_Data_d_size(scnDataPtr, scnDataBufSize);
|
||||
JNILibELFAPI.set_Data_d_off(scnDataPtr, 0);
|
||||
JNILibELFAPI.set_Data_d_type(scnDataPtr, dataType.intValue());
|
||||
JNILibELFAPI.set_Data_d_version(scnDataPtr, ELF.EV_CURRENT);
|
||||
|
||||
JNILibELFAPI.set_Shdr_sh_type(elfClass, scnHdrPtr, scnType);
|
||||
JNILibELFAPI.set_Shdr_sh_flags(elfClass, scnHdrPtr, scnFlags);
|
||||
JNILibELFAPI.set_Shdr_sh_entsize(elfClass, scnHdrPtr, 0); // TODO: Is this right??
|
||||
JNILibELFAPI.set_Shdr_sh_link(elfClass, scnHdrPtr, scnLink);
|
||||
JNILibELFAPI.set_Shdr_sh_info(elfClass, scnHdrPtr, scnInfo);
|
||||
|
||||
// Add hash section to section pointer list
|
||||
int index = JNILibELFAPI.elf_ndxscn(scnPtr);
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ELF symbol entry for a symbol with the given properties.
|
||||
*
|
||||
* @param name name of the section in which symName is referenced
|
||||
* @param type type of symName
|
||||
* @param bind binding of symName
|
||||
* @param secHdrIndex section header index of the section in which symName is referenced
|
||||
* (st_shndx of ELF symbol entry)
|
||||
* @param size symName size (st_size of ELF symbol entry)
|
||||
* @param value symName value (st_value of ELF symbol entry)
|
||||
* @param isLocal true if symbol is local.
|
||||
*/
|
||||
public ELFSymbol createELFSymbolEntry(String name, int type, int bind, int secHdrIndex, int size, int value, boolean isLocal) {
|
||||
// Get the current symbol index and append symbol name to string table.
|
||||
int index;
|
||||
if (name.isEmpty()) {
|
||||
index = 0;
|
||||
} else {
|
||||
// NOTE: The +1 comes from the null symbol!
|
||||
// We can't trust strTabContent.length() since that is chars (UTF16), keep track of
|
||||
// bytes on our own.
|
||||
index = strTabNrOfBytes + 1;
|
||||
strTabContent.append(name).append('\0');
|
||||
strTabNrOfBytes += name.getBytes(StandardCharsets.UTF_8).length + 1;
|
||||
}
|
||||
|
||||
// Create ELF symbol entry
|
||||
long address = JNILibELFAPI.create_sym_entry(elfClass, index, type, bind, secHdrIndex, size, value);
|
||||
if (address == 0) {
|
||||
throw new InternalError("create_sym_entry failed");
|
||||
}
|
||||
Pointer ptr = new Pointer(address);
|
||||
|
||||
if (isLocal) {
|
||||
final int localIndex = localSymbolIndex.size();
|
||||
ELFSymbol symbol = new ELFSymbol(name, localIndex, ptr, isLocal);
|
||||
localSymbolIndex.add(symbol);
|
||||
return symbol;
|
||||
} else {
|
||||
final int globalIndex = globalSymbolIndex.size();
|
||||
ELFSymbol symbol = new ELFSymbol(name, globalIndex, ptr, isLocal);
|
||||
globalSymbolIndex.add(symbol);
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ELF relocation entry for given symbol {@code name} to section {@code secname}.
|
||||
*
|
||||
* @param container the section
|
||||
* @param offset offset into the section contents at which the relocation needs to be applied
|
||||
* @param type ELF type of the relocation entry
|
||||
* @param addend Addend for for relocation of type reloca
|
||||
*/
|
||||
public void createELFRelocationEntry(ELFContainer container, int offset, int type, int addend, ELFSymbol elfSymbol) {
|
||||
// Get the index of the symbol.
|
||||
int index;
|
||||
if (elfSymbol.isLocal()) {
|
||||
index = elfSymbol.getIndex();
|
||||
} else {
|
||||
/*
|
||||
* For global symbol entries the index will be offset by the number of local symbols
|
||||
* which will be listed first in the symbol table.
|
||||
*/
|
||||
index = elfSymbol.getIndex() + localSymbolIndex.size();
|
||||
}
|
||||
|
||||
long address = JNILibELFAPI.create_reloc_entry(elfClass, offset, index, type, addend, createReloca);
|
||||
if (address == 0) {
|
||||
throw new InternalError("create_reloc_entry failed");
|
||||
}
|
||||
Pointer ptr = new Pointer(address);
|
||||
/*
|
||||
* If section name associated with this symbol is set to undefined i.e., secname is null,
|
||||
* symIndex is undef i.e., 0.
|
||||
*/
|
||||
if (relocTables.get(container) == null) {
|
||||
// Allocate a new table and add it to the hash table of reloc tables
|
||||
relocTables.put(container, new ArrayList<>());
|
||||
}
|
||||
|
||||
// Add the entry
|
||||
relocTables.get(container).add(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes native libelf function loff_t elf_update (Elf *elfPtr, Elf_Cmd cmd).
|
||||
*
|
||||
* @param cmd command
|
||||
* @return return value of the native function called
|
||||
*/
|
||||
public boolean elfUpdate(LibELF.Elf_Cmd cmd) {
|
||||
JNILibELFAPI.elf_update(elfPtr, cmd.intValue());
|
||||
// TODO: Error checking; look at the return value of elf_update
|
||||
// and call elf_errmsg appropriately.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function that invokes int elf_end (Elf *elfPtr). and closes ELF output file
|
||||
* descriptor
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public boolean elfEnd() {
|
||||
// Finish ELF processing
|
||||
JNILibELFAPI.elf_end(elfPtr);
|
||||
// Close file descriptor
|
||||
JNILibELFAPI.close(outFileDesc);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.jnilibelf;
|
||||
|
||||
/**
|
||||
* Class that abstracts ELF relocations.
|
||||
*
|
||||
*/
|
||||
public interface JNIELFRelocation {
|
||||
int R_UNDEF = -1;
|
||||
|
||||
/**
|
||||
* x86-specific relocation types.
|
||||
*
|
||||
*/
|
||||
public interface I386 {
|
||||
/* i386 relocs. */
|
||||
|
||||
int R_386_NONE = 0; /* No reloc */
|
||||
int R_386_32 = 1; /* Direct 32 bit */
|
||||
int R_386_PC32 = 2; /* PC relative 32 bit */
|
||||
int R_386_GOT32 = 3; /* 32 bit GOT entry */
|
||||
int R_386_PLT32 = 4; /* 32 bit PLT address */
|
||||
int R_386_COPY = 5; /* Copy symbol at runtime */
|
||||
int R_386_GLOB_DAT = 6; /* Create GOT entry */
|
||||
int R_386_JMP_SLOT = 7; /* Create PLT entry */
|
||||
int R_386_RELATIVE = 8; /* Adjust by program base */
|
||||
int R_386_GOTOFF = 9; /* 32 bit offset to GOT */
|
||||
int R_386_GOTPC = 10; /* 32 bit PC relative offset to GOT */
|
||||
int R_386_32PLT = 11;
|
||||
int R_386_TLS_TPOFF = 14; /* Offset in static TLS block */
|
||||
int R_386_TLS_IE = 15; /* Address of GOT entry for static TLS block offset */
|
||||
int R_386_TLS_GOTIE = 16; /* GOT entry for static TLS block offset */
|
||||
int R_386_TLS_LE = 17; /* Offset relative to static TLS block */
|
||||
int R_386_TLS_GD = 18; /* Direct 32 bit for GNU version of general dynamic thread local data */
|
||||
int R_386_TLS_LDM = 19; /*
|
||||
* Direct 32 bit for GNU version of local dynamic thread local data
|
||||
* in LE code
|
||||
*/
|
||||
int R_386_16 = 20;
|
||||
int R_386_PC16 = 21;
|
||||
int R_386_8 = 22;
|
||||
int R_386_PC8 = 23;
|
||||
int R_386_TLS_GD_32 = 24; /* Direct 32 bit for general dynamic thread local data */
|
||||
int R_386_TLS_GD_PUSH = 25; /* Tag for pushl in GD TLS code */
|
||||
int R_386_TLS_GD_CALL = 26; /* Relocation for call to __tls_get_addr() */
|
||||
int R_386_TLS_GD_POP = 27; /* Tag for popl in GD TLS code */
|
||||
int R_386_TLS_LDM_32 = 28; /* Direct 32 bit for local dynamic thread local data in LE code */
|
||||
int R_386_TLS_LDM_PUSH = 29; /* Tag for pushl in LDM TLS code */
|
||||
int R_386_TLS_LDM_CALL = 30; /* Relocation for call to __tls_get_addr() in LDM code */
|
||||
int R_386_TLS_LDM_POP = 31; /* Tag for popl in LDM TLS code */
|
||||
int R_386_TLS_LDO_32 = 32; /* Offset relative to TLS block */
|
||||
int R_386_TLS_IE_32 = 33; /* GOT entry for negated static TLS block offset */
|
||||
int R_386_TLS_LE_32 = 34; /* Negated offset relative to static TLS block */
|
||||
int R_386_TLS_DTPMOD32 = 35; /* ID of module containing symbol */
|
||||
int R_386_TLS_DTPOFF32 = 36; /* Offset in TLS block */
|
||||
int R_386_TLS_TPOFF32 = 37; /* Negated offset in static TLS block */
|
||||
int R_386_SIZE32 = 38; /* 32-bit symbol size */
|
||||
int R_386_TLS_GOTDESC = 39; /* GOT offset for TLS descriptor. */
|
||||
int R_386_TLS_DESC_CALL = 40; /* Marker of call through TLS descriptor for relaxation. */
|
||||
int R_386_TLS_DESC = 41; /*
|
||||
* TLS descriptor containing pointer to code and to argument,
|
||||
* returning the TLS offset for the symbol.
|
||||
*/
|
||||
int R_386_IRELATIVE = 42; /* Adjust indirectly by program base */
|
||||
/* Keep this the last entry. */
|
||||
int R_386_NUM = 43;
|
||||
}
|
||||
|
||||
/**
|
||||
* x86_64-specific relocation types.
|
||||
*/
|
||||
public interface X86_64 {
|
||||
/* AMD x86-64 relocations. */
|
||||
int R_X86_64_NONE = 0; /* No reloc */
|
||||
int R_X86_64_64 = 1; /* Direct 64 bit */
|
||||
int R_X86_64_PC32 = 2; /* PC relative 32 bit signed */
|
||||
int R_X86_64_GOT32 = 3; /* 32 bit GOT entry */
|
||||
int R_X86_64_PLT32 = 4; /* 32 bit PLT address */
|
||||
int R_X86_64_COPY = 5; /* Copy symbol at runtime */
|
||||
int R_X86_64_GLOB_DAT = 6; /* Create GOT entry */
|
||||
int R_X86_64_JUMP_SLOT = 7; /* Create PLT entry */
|
||||
int R_X86_64_RELATIVE = 8; /* Adjust by program base */
|
||||
int R_X86_64_GOTPCREL = 9; /* 32 bit signed PC relative offset to GOT */
|
||||
int R_X86_64_32 = 10; /* Direct 32 bit zero extended */
|
||||
int R_X86_64_32S = 11; /* Direct 32 bit sign extended */
|
||||
int R_X86_64_16 = 12; /* Direct 16 bit zero extended */
|
||||
int R_X86_64_PC16 = 13; /* 16 bit sign extended pc relative */
|
||||
int R_X86_64_8 = 14; /* Direct 8 bit sign extended */
|
||||
int R_X86_64_PC8 = 15; /* 8 bit sign extended pc relative */
|
||||
int R_X86_64_DTPMOD64 = 16; /* ID of module containing symbol */
|
||||
int R_X86_64_DTPOFF64 = 17; /* Offset in module's TLS block */
|
||||
int R_X86_64_TPOFF64 = 18; /* Offset in initial TLS block */
|
||||
int R_X86_64_TLSGD = 19; /*
|
||||
* 32 bit signed PC relative offset to two GOT entries for GD
|
||||
* symbol
|
||||
*/
|
||||
int R_X86_64_TLSLD = 20; /*
|
||||
* 32 bit signed PC relative offset to two GOT entries for LD
|
||||
* symbol
|
||||
*/
|
||||
int R_X86_64_DTPOFF32 = 21; /* Offset in TLS block */
|
||||
int R_X86_64_GOTTPOFF = 22; /*
|
||||
* 32 bit signed PC relative offset to GOT entry for IE symbol
|
||||
*/
|
||||
int R_X86_64_TPOFF32 = 23; /* Offset in initial TLS block */
|
||||
int R_X86_64_PC64 = 24; /* PC relative 64 bit */
|
||||
int R_X86_64_GOTOFF64 = 25; /* 64 bit offset to GOT */
|
||||
int R_X86_64_GOTPC32 = 26; /* 32 bit signed pc relative offset to GOT */
|
||||
int R_X86_64_GOT64 = 27; /* 64-bit GOT entry offset */
|
||||
int R_X86_64_GOTPCREL64 = 28; /* 64-bit PC relative offset to GOT entry */
|
||||
int R_X86_64_GOTPC64 = 29; /* 64-bit PC relative offset to GOT */
|
||||
int R_X86_64_GOTPLT64 = 30; /* like GOT64, says PLT entry needed */
|
||||
int R_X86_64_PLTOFF64 = 31; /* 64-bit GOT relative offset to PLT entry */
|
||||
int R_X86_64_SIZE32 = 32; /* Size of symbol plus 32-bit addend */
|
||||
int R_X86_64_SIZE64 = 33; /* Size of symbol plus 64-bit addend */
|
||||
int R_X86_64_GOTPC32_TLSDESC = 34; /* GOT offset for TLS descriptor. */
|
||||
int R_X86_64_TLSDESC_CALL = 35; /*
|
||||
* Marker for call through TLS descriptor.
|
||||
*/
|
||||
int R_X86_64_TLSDESC = 36; /* TLS descriptor. */
|
||||
int R_X86_64_IRELATIVE = 37; /* Adjust indirectly by program base */
|
||||
int R_X86_64_RELATIVE64 = 38; /* 64-bit adjust by program base */
|
||||
|
||||
int R_X86_64_NUM = 39;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.jnilibelf;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.ELF;
|
||||
|
||||
/**
|
||||
* Class that abstracts ELF target details.
|
||||
*
|
||||
*/
|
||||
public class JNIELFTargetInfo {
|
||||
/**
|
||||
* ELF Class of the target.
|
||||
*/
|
||||
private static final int elfClass;
|
||||
/**
|
||||
* Target architecture.
|
||||
*/
|
||||
private static final int arch;
|
||||
/**
|
||||
* Architecture endian-ness.
|
||||
*/
|
||||
private static final int endian;
|
||||
|
||||
/**
|
||||
* Target OS string.
|
||||
*/
|
||||
private static final String osName;
|
||||
|
||||
static {
|
||||
// Find the target arch details
|
||||
String archStr = System.getProperty("os.arch").toLowerCase();
|
||||
String datamodelStr = System.getProperty("sun.arch.data.model");
|
||||
|
||||
if (datamodelStr.equals("32")) {
|
||||
elfClass = ELF.ELFCLASS32;
|
||||
} else if (datamodelStr.equals("64")) {
|
||||
elfClass = ELF.ELFCLASS64;
|
||||
} else {
|
||||
System.out.println("Failed to discover ELF class!");
|
||||
elfClass = ELF.ELFCLASSNONE;
|
||||
}
|
||||
|
||||
ByteOrder bo = ByteOrder.nativeOrder();
|
||||
if (bo == ByteOrder.LITTLE_ENDIAN) {
|
||||
endian = ELF.ELFDATA2LSB;
|
||||
} else if (bo == ByteOrder.BIG_ENDIAN) {
|
||||
endian = ELF.ELFDATA2MSB;
|
||||
} else {
|
||||
System.out.println("Failed to discover endian-ness!");
|
||||
endian = ELF.ELFDATANONE;
|
||||
}
|
||||
|
||||
if (archStr.equals("x86")) {
|
||||
arch = ELF.EM_386;
|
||||
} else if (archStr.equals("amd64") || archStr.equals("x86_64")) {
|
||||
arch = ELF.EM_X64_64;
|
||||
} else if (archStr.equals("sparcv9")) {
|
||||
arch = ELF.EM_SPARCV9;
|
||||
} else {
|
||||
System.out.println("Unsupported architecture " + archStr);
|
||||
arch = ELF.EM_NONE;
|
||||
}
|
||||
|
||||
osName = System.getProperty("os.name").toLowerCase();
|
||||
}
|
||||
|
||||
public static int getELFArch() {
|
||||
return arch;
|
||||
}
|
||||
|
||||
public static int getELFClass() {
|
||||
return elfClass;
|
||||
}
|
||||
|
||||
public static int getELFEndian() {
|
||||
return endian;
|
||||
}
|
||||
|
||||
public static String getOsName() {
|
||||
return osName;
|
||||
}
|
||||
|
||||
public static int createReloca() {
|
||||
switch (arch) {
|
||||
case ELF.EM_X64_64:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static int sizeOfSymtabEntry() {
|
||||
return JNILibELFAPI.size_of_Sym(elfClass);
|
||||
}
|
||||
|
||||
public static int sizeOfRelocEntry() {
|
||||
if (createReloca() == 1) {
|
||||
return JNILibELFAPI.size_of_Rela(elfClass);
|
||||
} else {
|
||||
return JNILibELFAPI.size_of_Rel(elfClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,677 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.jnilibelf;
|
||||
|
||||
public class JNILibELFAPI {
|
||||
|
||||
static {
|
||||
System.loadLibrary("jelfshim");
|
||||
}
|
||||
|
||||
/**
|
||||
* Definitions for file open.
|
||||
*/
|
||||
public static enum OpenFlags {
|
||||
O_RDONLY(0x0),
|
||||
O_WRONLY(0x1),
|
||||
O_RDWR(0x2),
|
||||
O_CREAT(0x40);
|
||||
|
||||
private final int intVal;
|
||||
|
||||
private OpenFlags(int v) {
|
||||
intVal = v;
|
||||
}
|
||||
|
||||
public int intValue() {
|
||||
return intVal;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Definitions reflecting those in elf.h.
|
||||
*
|
||||
*/
|
||||
public interface ELF {
|
||||
int EI_NIDENT = 16;
|
||||
|
||||
int EI_CLASS = 4; /* File class byte index */
|
||||
int ELFCLASSNONE = 0; /* Invalid class */
|
||||
int ELFCLASS32 = 1; /* 32-bit objects */
|
||||
int ELFCLASS64 = 2; /* 64-bit objects */
|
||||
int ELFCLASSNUM = 3;
|
||||
|
||||
int EI_DATA = 5; /* Data encoding byte index */
|
||||
int ELFDATANONE = 0; /* Invalid data encoding */
|
||||
int ELFDATA2LSB = 1; /* 2's complement, little endian */
|
||||
int ELFDATA2MSB = 2; /* 2's complement, big endian */
|
||||
int ELFDATANUM = 3;
|
||||
|
||||
// Legal architecture values for e_machine (add others as needed)
|
||||
int EM_NONE = 0; /* No machine */
|
||||
int EM_SPARC = 2; /* SUN SPARC */
|
||||
int EM_386 = 3; /* Intel 80386 */
|
||||
int EM_SPARCV9 = 43; /* SPARC v9 64-bit */
|
||||
int EM_X64_64 = 62; /* AMD x86-64 architecture */
|
||||
|
||||
/* Legal values for e_type (object file type). */
|
||||
|
||||
int ET_NONE = 0; /* No file type */
|
||||
int ET_REL = 1; /* Relocatable file */
|
||||
int ET_EXEC = 2; /* Executable file */
|
||||
int ET_DYN = 3; /* Shared object file */
|
||||
int ET_CORE = 4; /* Core file */
|
||||
int ET_NUM = 5; /* Number of defined types */
|
||||
int ET_LOOS = 0xfe00; /* OS-specific range start */
|
||||
int ET_HIOS = 0xfeff; /* OS-specific range end */
|
||||
int ET_LOPROC = 0xff00; /* Processor-specific range start */
|
||||
int ET_HIPROC = 0xffff; /* Processor-specific range end */
|
||||
|
||||
/* Legal values for e_version (version). */
|
||||
|
||||
int EV_NONE = 0; /* Invalid ELF version */
|
||||
int EV_CURRENT = 1; /* Current version */
|
||||
int EV_NUM = 2;
|
||||
|
||||
/* Legal values for p_type (segment type). */
|
||||
|
||||
int PT_NULL = 0; /* Program header table entry unused */
|
||||
int PT_LOAD = 1; /* Loadable program segment */
|
||||
int PT_DYNAMIC = 2; /* Dynamic linking information */
|
||||
int PT_INTERP = 3; /* Program interpreter */
|
||||
int PT_NOTE = 4; /* Auxiliary information */
|
||||
int PT_SHLIB = 5; /* Reserved */
|
||||
int PT_PHDR = 6; /* Entry for header table itself */
|
||||
int PT_TLS = 7; /* Thread-local storage segment */
|
||||
int PT_NUM = 8; /* Number of defined types */
|
||||
int PT_LOOS = 0x60000000; /* Start of OS-specific */
|
||||
int PT_GNU_EH_FRAME = 0x6474e550; /* GCC .eh_frame_hdr segment */
|
||||
int PT_GNU_STACK = 0x6474e551; /* Indicates stack executability */
|
||||
int PT_GNU_RELRO = 0x6474e552; /* Read-only after relocation */
|
||||
int PT_LOSUNW = 0x6ffffffa;
|
||||
int PT_SUNWBSS = 0x6ffffffa; /* Sun Specific segment */
|
||||
int PT_SUNWSTACK = 0x6ffffffb; /* Stack segment */
|
||||
int PT_HISUNW = 0x6fffffff;
|
||||
int PT_HIOS = 0x6fffffff; /* End of OS-specific */
|
||||
int PT_LOPROC = 0x70000000; /* Start of processor-specific */
|
||||
int PT_HIPROC = 0x7fffffff; /* End of processor-specific */
|
||||
|
||||
/* Special section indices. */
|
||||
|
||||
int SHN_UNDEF = 0; /* Undefined section */
|
||||
int SHN_LORESERVE = 0xff00; /* Start of reserved indices */
|
||||
int SHN_LOPROC = 0xff00; /* Start of processor-specific */
|
||||
int SHN_BEFORE = 0xff00; /* Order section before all others (Solaris). */
|
||||
int SHN_AFTER = 0xff01; /* Order section after all others (Solaris). */
|
||||
int SHN_HIPROC = 0xff1f; /* End of processor-specific */
|
||||
int SHN_LOOS = 0xff20; /* Start of OS-specific */
|
||||
int SHN_HIOS = 0xff3f; /* End of OS-specific */
|
||||
int SHN_ABS = 0xfff1; /* Associated symbol is absolute */
|
||||
int SHN_COMMON = 0xfff2; /* Associated symbol is common */
|
||||
int SHN_XINDEX = 0xffff; /* Index is in extra table. */
|
||||
int SHN_HIRESERVE = 0xffff; /* End of reserved indices */
|
||||
|
||||
/* Legal values for sh_type (section type). */
|
||||
|
||||
int SHT_NULL = 0; /* Section header table entry unused */
|
||||
int SHT_PROGBITS = 1; /* Program data */
|
||||
int SHT_SYMTAB = 2; /* Symbol table */
|
||||
int SHT_STRTAB = 3; /* String table */
|
||||
int SHT_RELA = 4; /* Relocation entries with addends */
|
||||
int SHT_HASH = 5; /* Symbol hash table */
|
||||
int SHT_DYNAMIC = 6; /* Dynamic linking information */
|
||||
int SHT_NOTE = 7; /* Notes */
|
||||
int SHT_NOBITS = 8; /* Program space with no data (bss) */
|
||||
int SHT_REL = 9; /* Relocation entries, no addends */
|
||||
int SHT_SHLIB = 10; /* Reserved */
|
||||
int SHT_DYNSYM = 11; /* Dynamic linker symbol table */
|
||||
int SHT_INIT_ARRAY = 14; /* Array of constructors */
|
||||
int SHT_FINI_ARRAY = 15; /* Array of destructors */
|
||||
int SHT_PREINIT_ARRAY = 16; /* Array of pre-constructors */
|
||||
int SHT_GROUP = 17; /* Section group */
|
||||
int SHT_SYMTAB_SHNDX = 18; /* Extended section indeces */
|
||||
int SHT_NUM = 19; /* Number of defined types. */
|
||||
int SHT_LOOS = 0x60000000; /* Start OS-specific. */
|
||||
int SHT_GNU_ATTRIBUTES = 0x6ffffff5; /* Object attributes. */
|
||||
int SHT_GNU_HASH = 0x6ffffff6; /* GNU-style hash table. */
|
||||
int SHT_GNU_LIBLIST = 0x6ffffff7; /* Prelink library list */
|
||||
int SHT_CHECKSUM = 0x6ffffff8; /* Checksum for DSO content. */
|
||||
int SHT_LOSUNW = 0x6ffffffa; /* Sun-specific low bound. */
|
||||
int SHT_SUNW_move = 0x6ffffffa;
|
||||
int SHT_SUNW_COMDAT = 0x6ffffffb;
|
||||
int SHT_SUNW_syminfo = 0x6ffffffc;
|
||||
int SHT_GNU_verdef = 0x6ffffffd; /* Version definition section. */
|
||||
int SHT_GNU_verneed = 0x6ffffffe; /* Version needs section. */
|
||||
int SHT_GNU_versym = 0x6fffffff; /* Version symbol table. */
|
||||
int SHT_HISUNW = 0x6fffffff; /* Sun-specific high bound. */
|
||||
int SHT_HIOS = 0x6fffffff; /* End OS-specific type */
|
||||
int SHT_LOPROC = 0x70000000; /* Start of processor-specific */
|
||||
int SHT_HIPROC = 0x7fffffff; /* End of processor-specific */
|
||||
int SHT_LOUSER = 0x80000000; /* Start of application-specific */
|
||||
int SHT_HIUSER = 0x8fffffff; /* End of application-specific */
|
||||
|
||||
/* Legal values for sh_flags (section flags). */
|
||||
|
||||
int SHF_WRITE = (1 << 0); /* Writable */
|
||||
int SHF_ALLOC = (1 << 1); /* Occupies memory during execution */
|
||||
int SHF_EXECINSTR = (1 << 2); /* Executable */
|
||||
int SHF_MERGE = (1 << 4); /* Might be merged */
|
||||
int SHF_STRINGS = (1 << 5); /* Contains nul-terminated strings */
|
||||
int SHF_INFO_LINK = (1 << 6); /* `sh_info' contains SHT index */
|
||||
int SHF_LINK_ORDER = (1 << 7); /* Preserve order after combining */
|
||||
int SHF_OS_NONCONFORMING = (1 << 8); /* Non-standard OS specific handling required */
|
||||
int SHF_GROUP = (1 << 9); /* Section is member of a group. */
|
||||
int SHF_TLS = (1 << 10); /* Section hold thread-local data. */
|
||||
int SHF_MASKOS = 0x0ff00000; /* OS-specific. */
|
||||
int SHF_MASKPROC = 0xf0000000; /* Processor-specific */
|
||||
int SHF_ORDERED = (1 << 30); /* Special ordering requirement (Solaris). */
|
||||
int SHF_EXCLUDE = (1 << 31); /*
|
||||
* Section is excluded unless referenced or allocated
|
||||
* (Solaris).
|
||||
*/
|
||||
|
||||
/* Legal values for ST_BIND subfield of st_info (symbol binding). */
|
||||
|
||||
int STB_LOCAL = 0; /* Local symbol */
|
||||
int STB_GLOBAL = 1; /* Global symbol */
|
||||
int STB_WEAK = 2; /* Weak symbol */
|
||||
int STB_NUM = 3; /* Number of defined types. */
|
||||
int STB_LOOS = 10; /* Start of OS-specific */
|
||||
int STB_GNU_UNIQUE = 10; /* Unique symbol. */
|
||||
int STB_HIOS = 12; /* End of OS-specific */
|
||||
int STB_LOPROC = 13; /* Start of processor-specific */
|
||||
int STB_HIPROC = 15; /* End of processor-specific */
|
||||
|
||||
/* Legal values for ST_TYPE subfield of st_info (symbol type). */
|
||||
|
||||
int STT_NOTYPE = 0; /* Symbol type is unspecified */
|
||||
int STT_OBJECT = 1; /* Symbol is a data object */
|
||||
int STT_FUNC = 2; /* Symbol is a code object */
|
||||
int STT_SECTION = 3; /* Symbol associated with a section */
|
||||
int STT_FILE = 4; /* Symbol's name is file name */
|
||||
int STT_COMMON = 5; /* Symbol is a common data object */
|
||||
int STT_TLS = 6; /* Symbol is thread-local data object */
|
||||
int STT_NUM = 7; /* Number of defined types. */
|
||||
int STT_LOOS = 10; /* Start of OS-specific */
|
||||
int STT_GNU_IFUNC = 10; /* Symbol is indirect code object */
|
||||
int STT_HIOS = 12; /* End of OS-specific */
|
||||
int STT_LOPROC = 13; /* Start of processor-specific */
|
||||
int STT_HIPROC = 15; /* End of processor-specific */
|
||||
}
|
||||
|
||||
/**
|
||||
* Definitions reflecting those in libelf.h.
|
||||
*
|
||||
*/
|
||||
public interface LibELF {
|
||||
|
||||
public static enum Elf_Cmd {
|
||||
ELF_C_NULL("NULL"), /* Nothing, terminate, or compute only. */
|
||||
ELF_C_READ("READ"), /* Read .. */
|
||||
ELF_C_RDWR("RDWR"), /* Read and write .. */
|
||||
ELF_C_WRITE("WRITE"), /* Write .. */
|
||||
ELF_C_CLR("CLR"), /* Clear flag. */
|
||||
ELF_C_SET("SET"), /* Set flag. */
|
||||
ELF_C_FDDONE("FDDONE"), /*
|
||||
* Signal that file descriptor will not be used anymore.
|
||||
*/
|
||||
ELF_C_FDREAD("FDREAD"), /*
|
||||
* Read rest of data so that file descriptor is not used
|
||||
* anymore.
|
||||
*/
|
||||
/* The following are Linux-only extensions. */
|
||||
ELF_C_READ_MMAP("READ_MMAP"), /* Read, but mmap the file if possible. */
|
||||
ELF_C_RDWR_MMAP("RDWR_MMAP"), /* Read and write, with mmap. */
|
||||
ELF_C_WRITE_MMAP("WRITE_MMAP"), /* Write, with mmap. */
|
||||
ELF_C_READ_MMAP_PRIVATE("READ_MMAP_PRIVATE"), /*
|
||||
* Read, but memory is writable, results
|
||||
* are not written to the file.
|
||||
*/
|
||||
ELF_C_EMPTY("EMPTY"), /* Copy basic file data but not the content. */
|
||||
/* The following are SunOS-only enums */
|
||||
ELF_C_WRIMAGE("WRIMAGE"),
|
||||
ELF_C_IMAGE("IMAGE"),
|
||||
/* Common last entry. */
|
||||
ELF_C_NUM("NUM");
|
||||
private final int intVal;
|
||||
private final String name;
|
||||
|
||||
private Elf_Cmd(String cmd) {
|
||||
name = "ELF_C_" + cmd;
|
||||
switch (cmd) {
|
||||
case "NULL":
|
||||
// ELF_C_NULL has the same enum ordinal on both Linux and SunOS
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_NULL.ordinal();
|
||||
break;
|
||||
|
||||
case "READ":
|
||||
// ELF_C_READ has the same enum ordinal on both Linux and SunOS
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_READ.ordinal();
|
||||
break;
|
||||
|
||||
// Enums defined in libelf.h of both Linux and SunOS
|
||||
// but with different ordinals
|
||||
case "RDWR":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_RDWR.ordinal();
|
||||
} else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_RDWR.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case "WRITE":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_WRITE.ordinal();
|
||||
} else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_WRITE.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case "CLR":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_CLR.ordinal();
|
||||
} else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_CLR.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case "SET":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_SET.ordinal();
|
||||
} else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_SET.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case "FDDONE":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_FDDONE.ordinal();
|
||||
} else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_FDDONE.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case "FDREAD":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_FDREAD.ordinal();
|
||||
} else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_FDREAD.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case "NUM":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_NUM.ordinal();
|
||||
} else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_NUM.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
// Linux-only Elf_Cmd enums
|
||||
case "READ_MMAP":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_READ_MMAP.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case "RDWR_MMAP":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_RDWR_MMAP.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case "WRITE_MMAP":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_WRITE_MMAP.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case "READ_MMAP_PRIVATE":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_READ_MMAP_PRIVATE.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case "EMPTY":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_EMPTY.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
// SunOS-only Elf_Cmd enums
|
||||
case "WRIMAGE":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_WRIMAGE.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
case "IMAGE":
|
||||
if (JNIELFTargetInfo.getOsName().equals("linux")) {
|
||||
intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_IMAGE.ordinal();
|
||||
} else {
|
||||
// Unsupported platform
|
||||
intVal = -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
intVal = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int intValue() {
|
||||
assert intVal != -1 : "enum " + name + "not supported on " + JNIELFTargetInfo.getOsName();
|
||||
return intVal;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum Elf_Type {
|
||||
ELF_T_BYTE(0), /* unsigned char */
|
||||
ELF_T_ADDR(1), /* Elf32_Addr, Elf64_Addr, ... */
|
||||
ELF_T_DYN(2), /* Dynamic section record. */
|
||||
ELF_T_EHDR(3), /* ELF header. */
|
||||
ELF_T_HALF(4), /* Elf32_Half, Elf64_Half, ... */
|
||||
ELF_T_OFF(5), /* Elf32_Off, Elf64_Off, ... */
|
||||
ELF_T_PHDR(6), /* Program header. */
|
||||
ELF_T_RELA(7), /* Relocation entry with addend. */
|
||||
ELF_T_REL(8), /* Relocation entry. */
|
||||
ELF_T_SHDR(9), /* Section header. */
|
||||
ELF_T_SWORD(10), /* Elf32_Sword, Elf64_Sword, ... */
|
||||
ELF_T_SYM(11), /* Symbol record. */
|
||||
ELF_T_WORD(12), /* Elf32_Word, Elf64_Word, ... */
|
||||
ELF_T_XWORD(13), /* Elf32_Xword, Elf64_Xword, ... */
|
||||
ELF_T_SXWORD(14), /* Elf32_Sxword, Elf64_Sxword, ... */
|
||||
ELF_T_VDEF(15), /* Elf32_Verdef, Elf64_Verdef, ... */
|
||||
ELF_T_VDAUX(16), /* Elf32_Verdaux, Elf64_Verdaux, ... */
|
||||
ELF_T_VNEED(17), /* Elf32_Verneed, Elf64_Verneed, ... */
|
||||
ELF_T_VNAUX(18), /* Elf32_Vernaux, Elf64_Vernaux, ... */
|
||||
ELF_T_NHDR(19), /* Elf32_Nhdr, Elf64_Nhdr, ... */
|
||||
ELF_T_SYMINFO(20), /* Elf32_Syminfo, Elf64_Syminfo, ... */
|
||||
ELF_T_MOVE(21), /* Elf32_Move, Elf64_Move, ... */
|
||||
ELF_T_LIB(22), /* Elf32_Lib, Elf64_Lib, ... */
|
||||
ELF_T_GNUHASH(23), /* GNU-style hash section. */
|
||||
ELF_T_AUXV(24), /* Elf32_auxv_t, Elf64_auxv_t, ... */
|
||||
/* Keep this the last entry. */
|
||||
ELF_T_NUM(25);
|
||||
|
||||
private final int intVal;
|
||||
|
||||
private Elf_Type(int v) {
|
||||
intVal = v;
|
||||
}
|
||||
|
||||
public int intValue() {
|
||||
return intVal;
|
||||
}
|
||||
}
|
||||
|
||||
/* Flags for the ELF structures. */
|
||||
int ELF_F_DIRTY = 0x1;
|
||||
int ELF_F_LAYOUT = 0x4;
|
||||
int ELF_F_PERMISSIVE = 0x8;
|
||||
|
||||
public static enum Elf_Kind {
|
||||
ELF_K_NONE(0), /* Unknown. */
|
||||
ELF_K_AR(1), /* Archive. */
|
||||
ELF_K_COFF(2), /* Stupid old COFF. */
|
||||
ELF_K_ELF(3), /* ELF file. */
|
||||
/* Keep this the last entry. */
|
||||
ELF_K_NUM(4);
|
||||
private final int intVal;
|
||||
|
||||
private Elf_Kind(int v) {
|
||||
intVal = v;
|
||||
}
|
||||
|
||||
public int intValue() {
|
||||
return intVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke native libelf function unsigned int elf_version (unsigned int v).
|
||||
*
|
||||
* @param v version
|
||||
* @return return value of native call
|
||||
*/
|
||||
// Checkstyle: stop method name check
|
||||
static native int elf_version(int v);
|
||||
|
||||
/**
|
||||
* Return version recorded in libelfshim.
|
||||
*
|
||||
* @return return version string
|
||||
*/
|
||||
// Checkstyle: stop method name check
|
||||
static native String elfshim_version();
|
||||
|
||||
/**
|
||||
* Invoke native libelf function Elf *elf_begin (int fildes, Elf_Cmd cmd, Elf *elfPtr).
|
||||
*
|
||||
* @param fildes open file descriptor
|
||||
* @param elfCRead command
|
||||
* @param elfHdrPtr pointer to ELF header
|
||||
* @return return value of native call
|
||||
*/
|
||||
static native Pointer elf_begin(int fildes, int elfCRead, Pointer elfHdrPtr);
|
||||
|
||||
/**
|
||||
* Invoke native libelf function elf_end (Elf *elfPtr).
|
||||
*
|
||||
* @param elfPtr pointer to ELF header
|
||||
* @return return value of native call
|
||||
*/
|
||||
static native int elf_end(Pointer elfPtr);
|
||||
|
||||
/**
|
||||
* Invoke native libelf function elf_end (Elf *elfPtr).
|
||||
*
|
||||
* @param elfPtr pointer to ELF header
|
||||
* @return return value of native call
|
||||
*/
|
||||
static native int elf_kind(Pointer elfPtr);
|
||||
|
||||
/**
|
||||
* Invoke native libelf function unsigned int elf_flagphdr (Elf *elf, Elf_Cmd cmd, unsigned int
|
||||
* flags).
|
||||
*
|
||||
* @param elfPtr Pointer to ELF descriptor
|
||||
* @param cmd command
|
||||
* @param flags flags
|
||||
* @return return value of native call
|
||||
*/
|
||||
static native int elf_flagphdr(Pointer elfPtr, int cmd, int flags);
|
||||
|
||||
/**
|
||||
* Invoke native libelf function Elf_Scn *elf_newscn (Elf *elfPtr).
|
||||
*
|
||||
* @param elfPtr Elf header pointer
|
||||
* @return return value of native call
|
||||
*/
|
||||
static native Pointer elf_newscn(Pointer elfPtr);
|
||||
|
||||
/**
|
||||
* Invoke native libelf function Elf_Data *elf_newdata (Elf_Scn *scn).
|
||||
*
|
||||
* @param scnPtr pointer to section for which the new data descriptor is to be created
|
||||
* @return return value of native call
|
||||
*/
|
||||
static native Pointer elf_newdata(Pointer scnPtr);
|
||||
|
||||
/**
|
||||
* Invoke native libelf function Elf64_Shdr *elf64_getshdr (Elf_Scn *scnPtr).
|
||||
*
|
||||
* @param scnPtr pointer to section whose header information is to be retrieved
|
||||
* @return return value of native call
|
||||
*/
|
||||
static native Pointer elf64_getshdr(Pointer scnPtr);
|
||||
|
||||
/**
|
||||
* Invoke native libelf function loff_t elf_update (Elf *elfPtr, Elf_Cmd cmd).
|
||||
*
|
||||
* @param elfPtr Pointer to ELF descriptor
|
||||
* @param cmd command
|
||||
* @return return value of native call
|
||||
*/
|
||||
static native long elf_update(Pointer elfPtr, int cmd);
|
||||
|
||||
/**
|
||||
* Invoke native libelf function char *elf_errmsg (int error).
|
||||
*
|
||||
* @param error error
|
||||
* @return return value of native call
|
||||
*/
|
||||
static native String elf_errmsg(int error);
|
||||
|
||||
/**
|
||||
* Invoke native libelf function size_t elf_ndxscn (Elf_Scn *scn).
|
||||
*
|
||||
* @param scn section pointer
|
||||
* @return return value of native call
|
||||
*/
|
||||
static native int elf_ndxscn(Pointer scn);
|
||||
|
||||
/**
|
||||
* GELF interfaces
|
||||
*/
|
||||
/**
|
||||
* Invoke native libelf function unsigned long int gelf_newehdr (Elf *elf, int elfClass).
|
||||
*
|
||||
* @param elf ELF Header pointer
|
||||
* @param elfclass ELF class
|
||||
* @return return value of native call boxed as a pointer
|
||||
*/
|
||||
static native Pointer gelf_newehdr(Pointer elf, int elfclass);
|
||||
|
||||
/**
|
||||
* Invoke native libelf function unsigned long int gelf_newphdr (Elf *elf, size_t phnum).
|
||||
*
|
||||
* @param elf ELF header pointer
|
||||
* @param phnum number of program headers
|
||||
* @return return value of native call boxed as a pointer
|
||||
*/
|
||||
static native Pointer gelf_newphdr(Pointer elf, int phnum);
|
||||
|
||||
/**
|
||||
* Miscellaneous convenience native methods that help peek and poke ELF data structures.
|
||||
*/
|
||||
static native int size_of_Sym(int elfClass);
|
||||
|
||||
static native int size_of_Rela(int elfClass);
|
||||
|
||||
static native int size_of_Rel(int elfClass);
|
||||
|
||||
static native void ehdr_set_data_encoding(Pointer ehdr, int val);
|
||||
|
||||
static native void set_Ehdr_e_machine(int elfclass, Pointer structPtr, int val);
|
||||
|
||||
static native void set_Ehdr_e_type(int elfclass, Pointer structPtr, int val);
|
||||
|
||||
static native void set_Ehdr_e_version(int elfclass, Pointer structPtr, int val);
|
||||
|
||||
static native void set_Ehdr_e_shstrndx(int elfclass, Pointer structPtr, int val);
|
||||
|
||||
static native void phdr_set_type_self(int elfclass, Pointer ehdr, Pointer phdr);
|
||||
|
||||
static native void set_Shdr_sh_name(int elfclass, Pointer structPtr, int val);
|
||||
|
||||
static native void set_Shdr_sh_type(int elfclass, Pointer structPtr, int val);
|
||||
|
||||
static native void set_Shdr_sh_flags(int elfclass, Pointer structPtr, int val);
|
||||
|
||||
static native void set_Shdr_sh_entsize(int elfclass, Pointer structPtr, int val);
|
||||
|
||||
static native void set_Shdr_sh_link(int elfclass, Pointer structPtr, int val);
|
||||
|
||||
static native void set_Shdr_sh_info(int elfclass, Pointer structPtr, int val);
|
||||
|
||||
static native void set_Data_d_align(Pointer structPtr, int val);
|
||||
|
||||
static native void set_Data_d_off(Pointer structPtr, int val);
|
||||
|
||||
static native void set_Data_d_buf(Pointer structPtr, Pointer val);
|
||||
|
||||
static native void set_Data_d_type(Pointer structPtr, int val);
|
||||
|
||||
static native void set_Data_d_size(Pointer structPtr, int val);
|
||||
|
||||
static native void set_Data_d_version(Pointer structPtr, int val);
|
||||
|
||||
static native long create_sym_entry(int elfclass, int index, int type, int bind, int shndx, int size, int value);
|
||||
|
||||
static native long create_reloc_entry(int elfclass, int roffset, int symtabIdx, int relocType, int raddend, int reloca);
|
||||
|
||||
/**
|
||||
* File Operations.
|
||||
*/
|
||||
static native int open_rw(String fileName);
|
||||
|
||||
static native int open(String fileName, int flags);
|
||||
|
||||
static native int open(String fileName, int flags, int mode);
|
||||
|
||||
static native int close(int fd);
|
||||
// Checkstyle: resume method name check
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.jnilibelf;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
import static jdk.tools.jaotc.jnilibelf.UnsafeAccess.UNSAFE;
|
||||
|
||||
public class Pointer {
|
||||
|
||||
private final long address;
|
||||
|
||||
public Pointer(long val) {
|
||||
address = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put (i.e., copy) content of byte array at consecutive addresses beginning at this Pointer.
|
||||
*
|
||||
* @param src source byte array
|
||||
*/
|
||||
public void put(byte[] src) {
|
||||
UNSAFE.copyMemory(src, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, address, src.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get (i.e., copy) content at this Pointer to the given byte array.
|
||||
*
|
||||
* @param dst destination byte array
|
||||
*/
|
||||
public void get(byte[] dst) {
|
||||
UNSAFE.copyMemory(null, address, dst, Unsafe.ARRAY_BYTE_BASE_OFFSET, dst.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read {@code readSize} number of bytes to copy them starting at {@code startIndex} of
|
||||
* {@code byteArray}
|
||||
*
|
||||
* @param byteArray target array to copy bytes
|
||||
* @param readSize number of bytes to copy
|
||||
* @param startIndex index of the array to start copy at
|
||||
*/
|
||||
public void copyBytesTo(byte[] byteArray, int readSize, int startIndex) {
|
||||
long end = (long)startIndex + (long)readSize;
|
||||
if (end > byteArray.length) {
|
||||
throw new IllegalArgumentException("writing beyond array bounds");
|
||||
}
|
||||
UNSAFE.copyMemory(null, address, byteArray, Unsafe.ARRAY_BYTE_BASE_OFFSET+startIndex, readSize);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.jnilibelf;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Package private access to the {@link Unsafe} capability.
|
||||
*/
|
||||
class UnsafeAccess {
|
||||
|
||||
static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.jnilibelf.linux;
|
||||
|
||||
/**
|
||||
* Represent Elf_Cmd enums defined in libelf.h on Linux as they slightly different from libelf.h on
|
||||
* SunOS.
|
||||
*/
|
||||
public enum Elf_Cmd {
|
||||
/** Nothing, terminate, or compute only. */
|
||||
ELF_C_NULL,
|
||||
|
||||
/** Read. */
|
||||
ELF_C_READ,
|
||||
|
||||
/** Read and write. */
|
||||
ELF_C_RDWR,
|
||||
|
||||
/** Write. */
|
||||
ELF_C_WRITE,
|
||||
|
||||
/** Clear flag. */
|
||||
ELF_C_CLR,
|
||||
|
||||
/** Set flag. */
|
||||
ELF_C_SET,
|
||||
|
||||
/**
|
||||
* Signal that file descriptor will not be used anymore.
|
||||
*/
|
||||
ELF_C_FDDONE,
|
||||
|
||||
/**
|
||||
* Read rest of data so that file descriptor is not used anymore.
|
||||
*/
|
||||
ELF_C_FDREAD,
|
||||
|
||||
/* The following are extensions. */
|
||||
|
||||
/** Read, but mmap the file if possible. */
|
||||
ELF_C_READ_MMAP,
|
||||
|
||||
/** Read and write, with mmap. */
|
||||
ELF_C_RDWR_MMAP,
|
||||
|
||||
/** Write, with mmap. */
|
||||
ELF_C_WRITE_MMAP,
|
||||
|
||||
/**
|
||||
* Read, but memory is writable, results are not written to the file.
|
||||
*/
|
||||
ELF_C_READ_MMAP_PRIVATE,
|
||||
|
||||
/** Copy basic file data but not the content. */
|
||||
ELF_C_EMPTY,
|
||||
|
||||
/** Keep this the last entry. */
|
||||
ELF_C_NUM;
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.jnilibelf.sunos;
|
||||
|
||||
/**
|
||||
* Represent Elf_Cmd enums defined in libelf.h on SunOS as they slightly different from libelf.h on
|
||||
* Linux.
|
||||
*/
|
||||
public enum Elf_Cmd {
|
||||
/** Must be first, 0. */
|
||||
ELF_C_NULL,
|
||||
|
||||
ELF_C_READ,
|
||||
ELF_C_WRITE,
|
||||
ELF_C_CLR,
|
||||
ELF_C_SET,
|
||||
ELF_C_FDDONE,
|
||||
ELF_C_FDREAD,
|
||||
ELF_C_RDWR,
|
||||
ELF_C_WRIMAGE,
|
||||
ELF_C_IMAGE,
|
||||
|
||||
/** Must be last. */
|
||||
ELF_C_NUM
|
||||
|
||||
}
|
||||
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc;
|
||||
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.graalvm.compiler.core.GraalCompiler;
|
||||
import org.graalvm.compiler.core.common.CompilationIdentifier;
|
||||
import org.graalvm.compiler.debug.Debug;
|
||||
import org.graalvm.compiler.debug.Debug.Scope;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.hotspot.HotSpotBackend;
|
||||
import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
|
||||
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
|
||||
import org.graalvm.compiler.java.GraphBuilderPhase;
|
||||
import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
|
||||
import org.graalvm.compiler.lir.phases.LIRSuites;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
|
||||
import org.graalvm.compiler.options.OptionValue;
|
||||
import org.graalvm.compiler.options.OptionValue.OverrideScope;
|
||||
import org.graalvm.compiler.phases.BasePhase;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.graalvm.compiler.phases.PhaseSuite;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
import org.graalvm.compiler.phases.tiers.Suites;
|
||||
|
||||
import jdk.vm.ci.code.InstalledCode;
|
||||
import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
|
||||
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.DefaultProfilingInfo;
|
||||
import jdk.vm.ci.meta.ProfilingInfo;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.TriState;
|
||||
|
||||
public class AOTBackend {
|
||||
|
||||
private final Main main;
|
||||
|
||||
private final HotSpotBackend backend;
|
||||
|
||||
private final HotSpotProviders providers;
|
||||
private final HotSpotCodeCacheProvider codeCache;
|
||||
private final PhaseSuite<HighTierContext> graphBuilderSuite;
|
||||
private final HighTierContext highTierContext;
|
||||
private final GraalFilters filters;
|
||||
|
||||
public AOTBackend(Main main, HotSpotBackend backend, GraalFilters filters) {
|
||||
this.main = main;
|
||||
this.backend = backend;
|
||||
this.filters = filters;
|
||||
providers = backend.getProviders();
|
||||
codeCache = providers.getCodeCache();
|
||||
graphBuilderSuite = initGraphBuilderSuite(backend);
|
||||
highTierContext = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.ALL);
|
||||
}
|
||||
|
||||
private Suites getSuites() {
|
||||
// create suites every time, as we modify options for the compiler
|
||||
return backend.getSuites().getDefaultSuites();
|
||||
}
|
||||
|
||||
private LIRSuites getLirSuites() {
|
||||
// create suites every time, as we modify options for the compiler
|
||||
return backend.getSuites().getDefaultLIRSuites();
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
public CompilationResult compileMethod(ResolvedJavaMethod resolvedMethod) {
|
||||
try (OverrideScope s = OptionValue.override(ImmutableCode, true, GeneratePIC, true)) {
|
||||
StructuredGraph graph = buildStructuredGraph(resolvedMethod);
|
||||
if (graph != null) {
|
||||
return compileGraph(resolvedMethod, graph);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a structured graph for the member.
|
||||
*
|
||||
* @param javaMethod method for whose code the graph is to be created
|
||||
* @return structured graph
|
||||
*/
|
||||
@SuppressWarnings("try")
|
||||
private StructuredGraph buildStructuredGraph(ResolvedJavaMethod javaMethod) {
|
||||
try (Scope s = Debug.scope("AOTParseMethod")) {
|
||||
StructuredGraph graph = new StructuredGraph(javaMethod, StructuredGraph.AllowAssumptions.NO, false, CompilationIdentifier.INVALID_COMPILATION_ID);
|
||||
graphBuilderSuite.apply(graph, highTierContext);
|
||||
return graph;
|
||||
} catch (Throwable e) {
|
||||
handleError(javaMethod, e, " (building graph)");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
private CompilationResult compileGraph(ResolvedJavaMethod resolvedMethod, StructuredGraph graph) {
|
||||
try (Scope s = Debug.scope("AOTCompileMethod")) {
|
||||
ProfilingInfo profilingInfo = DefaultProfilingInfo.get(TriState.FALSE);
|
||||
|
||||
final boolean isImmutablePIC = true;
|
||||
CompilationResult compilationResult = new CompilationResult(resolvedMethod.getName(), isImmutablePIC);
|
||||
|
||||
return GraalCompiler.compileGraph(graph, resolvedMethod, providers, backend, graphBuilderSuite, OptimisticOptimizations.ALL, profilingInfo, getSuites(), getLirSuites(),
|
||||
compilationResult, CompilationResultBuilderFactory.Default);
|
||||
|
||||
} catch (Throwable e) {
|
||||
handleError(resolvedMethod, e, " (compiling graph)");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the VM is a debug build.
|
||||
*
|
||||
* @return true is debug VM, false otherwise
|
||||
*/
|
||||
public boolean isDebugVM() {
|
||||
return backend.getRuntime().getVMConfig().cAssertions;
|
||||
}
|
||||
|
||||
private static PhaseSuite<HighTierContext> initGraphBuilderSuite(HotSpotBackend backend) {
|
||||
PhaseSuite<HighTierContext> graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
|
||||
ListIterator<BasePhase<? super HighTierContext>> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class);
|
||||
GraphBuilderConfiguration baseConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig();
|
||||
|
||||
// Use all default plugins.
|
||||
Plugins plugins = baseConfig.getPlugins();
|
||||
GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
|
||||
|
||||
iterator.next();
|
||||
iterator.remove();
|
||||
iterator.add(new GraphBuilderPhase(aotConfig));
|
||||
|
||||
return graphBuilderSuite;
|
||||
}
|
||||
|
||||
private void handleError(ResolvedJavaMethod resolvedMethod, Throwable e, String message) {
|
||||
String methodName = MiscUtils.uniqueMethodName(resolvedMethod);
|
||||
|
||||
if (main.options.debug) {
|
||||
main.printError("Failed compilation: " + methodName + ": " + e);
|
||||
}
|
||||
|
||||
// Ignore some exceptions when meta-compiling Graal.
|
||||
if (filters.shouldIgnoreException(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Main.writeLog("Failed compilation of method " + methodName + message);
|
||||
|
||||
if (!main.options.debug) {
|
||||
main.printError("Failed compilation: " + methodName + ": " + e);
|
||||
}
|
||||
|
||||
if (main.options.verbose) {
|
||||
e.printStackTrace(main.log);
|
||||
}
|
||||
|
||||
if (main.options.exitOnError) {
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public void printCompiledMethod(HotSpotResolvedJavaMethod resolvedMethod, CompilationResult compResult) {
|
||||
// This is really not installing the method.
|
||||
InstalledCode installedCode = codeCache.addCode(resolvedMethod, HotSpotCompiledCodeBuilder.createCompiledCode(null, null, compResult), null, null);
|
||||
String disassembly = codeCache.disassemble(installedCode);
|
||||
if (disassembly != null) {
|
||||
main.printlnDebug(disassembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.graalvm.compiler.core.GraalCompilerOptions;
|
||||
import org.graalvm.compiler.debug.Debug;
|
||||
import org.graalvm.compiler.debug.DebugEnvironment;
|
||||
import org.graalvm.compiler.debug.Management;
|
||||
import org.graalvm.compiler.debug.TTY;
|
||||
import org.graalvm.compiler.debug.internal.DebugScope;
|
||||
|
||||
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
|
||||
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import jdk.vm.ci.runtime.JVMCICompiler;
|
||||
|
||||
/**
|
||||
* Represents a task in the compile queue.
|
||||
*
|
||||
* This class encapsulates all Graal-specific information that is used during offline AOT
|
||||
* compilation of classes. It also defines methods that parse compilation result of Graal to create
|
||||
* target-independent representation {@code BinaryContainer} of the intended target binary.
|
||||
*/
|
||||
public class AOTCompilationTask implements Runnable, Comparable<Object> {
|
||||
|
||||
private static final AtomicInteger ids = new AtomicInteger();
|
||||
|
||||
private static final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) Management.getThreadMXBean();
|
||||
|
||||
private final Main main;
|
||||
|
||||
/**
|
||||
* The compilation id of this task.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
private final AOTCompiledClass holder;
|
||||
|
||||
/**
|
||||
* Method this task represents.
|
||||
*/
|
||||
private final ResolvedJavaMethod method;
|
||||
|
||||
private final AOTBackend aotBackend;
|
||||
|
||||
/**
|
||||
* The result of this compilation task.
|
||||
*/
|
||||
private CompiledMethodInfo result;
|
||||
|
||||
public AOTCompilationTask(Main main, AOTCompiledClass holder, ResolvedJavaMethod method, AOTBackend aotBackend) {
|
||||
this.main = main;
|
||||
this.id = ids.getAndIncrement();
|
||||
this.holder = holder;
|
||||
this.method = method;
|
||||
this.aotBackend = aotBackend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a method or a constructor.
|
||||
*/
|
||||
public void run() {
|
||||
// Ensure a JVMCI runtime is initialized prior to Debug being initialized as the former
|
||||
// may include processing command line options used by the latter.
|
||||
HotSpotJVMCIRuntime.runtime();
|
||||
|
||||
// Ensure a debug configuration for this thread is initialized
|
||||
if (Debug.isEnabled() && DebugScope.getConfig() == null) {
|
||||
DebugEnvironment.initialize(TTY.out);
|
||||
}
|
||||
AOTCompiler.logCompilation(MiscUtils.uniqueMethodName(method), "Compiling");
|
||||
|
||||
final long threadId = Thread.currentThread().getId();
|
||||
|
||||
final boolean printCompilation = GraalCompilerOptions.PrintCompilation.getValue() && !TTY.isSuppressed();
|
||||
final boolean printAfterCompilation = GraalCompilerOptions.PrintAfterCompilation.getValue() && !TTY.isSuppressed();
|
||||
if (printCompilation) {
|
||||
TTY.println(getMethodDescription() + "...");
|
||||
}
|
||||
|
||||
final long start;
|
||||
final long allocatedBytesBefore;
|
||||
if (printAfterCompilation || printCompilation) {
|
||||
start = System.currentTimeMillis();
|
||||
allocatedBytesBefore = printAfterCompilation || printCompilation ? threadMXBean.getThreadAllocatedBytes(threadId) : 0L;
|
||||
} else {
|
||||
start = 0L;
|
||||
allocatedBytesBefore = 0L;
|
||||
}
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
CompilationResult compResult = aotBackend.compileMethod(method);
|
||||
final long endTime = System.currentTimeMillis();
|
||||
|
||||
if (printAfterCompilation || printCompilation) {
|
||||
final long stop = System.currentTimeMillis();
|
||||
final int targetCodeSize = compResult != null ? compResult.getTargetCodeSize() : -1;
|
||||
final long allocatedBytesAfter = threadMXBean.getThreadAllocatedBytes(threadId);
|
||||
final long allocatedBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024;
|
||||
|
||||
if (printAfterCompilation) {
|
||||
TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dkB", stop - start, targetCodeSize, allocatedBytes));
|
||||
} else if (printCompilation) {
|
||||
TTY.println(String.format("%-6d JVMCI %-70s %-45s %-50s | %4dms %5dB %5dkB", getId(), "", "", "", stop - start, targetCodeSize, allocatedBytes));
|
||||
}
|
||||
}
|
||||
|
||||
if (compResult == null) {
|
||||
result = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// For now precision to the nearest second is sufficient.
|
||||
Main.writeLog(" Compile Time: " + TimeUnit.MILLISECONDS.toSeconds(endTime - startTime) + "secs");
|
||||
if (main.options.debug) {
|
||||
aotBackend.printCompiledMethod((HotSpotResolvedJavaMethod) method, compResult);
|
||||
}
|
||||
|
||||
result = new CompiledMethodInfo(compResult, new AOTHotSpotResolvedJavaMethod((HotSpotResolvedJavaMethod) method));
|
||||
}
|
||||
|
||||
private String getMethodDescription() {
|
||||
return String.format("%-6d JVMCI %-70s %-45s %-50s %s", getId(), method.getDeclaringClass().getName(), method.getName(), method.getSignature().toMethodDescriptor(),
|
||||
getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + getEntryBCI() + ") ");
|
||||
}
|
||||
|
||||
private int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getEntryBCI() {
|
||||
return JVMCICompiler.INVOCATION_ENTRY_BCI;
|
||||
}
|
||||
|
||||
public ResolvedJavaMethod getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the holder of this method as a {@link AOTCompiledClass}.
|
||||
*
|
||||
* @return the holder of this method
|
||||
*/
|
||||
public AOTCompiledClass getHolder() {
|
||||
return holder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result of this compilation task.
|
||||
*
|
||||
* @return result of this compilation task
|
||||
*/
|
||||
public CompiledMethodInfo getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Object obj) {
|
||||
AOTCompilationTask other = (AOTCompilationTask) obj;
|
||||
return this.id - other.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
AOTCompilationTask other = (AOTCompilationTask) obj;
|
||||
return (this.id == other.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 + id;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,377 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.tools.jaotc.binformat.BinaryContainer;
|
||||
import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Binding;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Kind;
|
||||
|
||||
import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
|
||||
import jdk.vm.ci.meta.ResolvedJavaField;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.ResolvedJavaType;
|
||||
|
||||
/**
|
||||
* Class encapsulating Graal-compiled output of a Java class. The compilation result of all methods
|
||||
* of a class {@code className} are maintained in an array list.
|
||||
*/
|
||||
public class AOTCompiledClass {
|
||||
|
||||
public static class AOTKlassData {
|
||||
int gotIndex; // Index (offset/8) to the got in the .metaspace.got section
|
||||
int classId; // Unique ID
|
||||
// Offset to compiled methods data in the .methods.offsets section.
|
||||
int compiledMethodsOffset;
|
||||
// Offset to dependent methods data.
|
||||
int dependentMethodsOffset;
|
||||
long fingerprint; // Class fingerprint
|
||||
|
||||
private final String name;
|
||||
private boolean isArray;
|
||||
|
||||
/**
|
||||
* List of dependent compiled methods which have a reference to this class.
|
||||
*/
|
||||
private ArrayList<CompiledMethodInfo> dependentMethods;
|
||||
|
||||
public AOTKlassData(BinaryContainer binaryContainer, String name, long fingerprint, int classId) {
|
||||
this.dependentMethods = new ArrayList<>();
|
||||
this.classId = classId;
|
||||
this.fingerprint = fingerprint;
|
||||
this.gotIndex = binaryContainer.addTwoSlotMetaspaceSymbol(name);
|
||||
this.compiledMethodsOffset = -1; // Not compiled classes do not have compiled methods.
|
||||
this.dependentMethodsOffset = -1;
|
||||
this.name = name;
|
||||
this.isArray = name.length() > 0 && name.charAt(0) == '[';
|
||||
}
|
||||
|
||||
public long getFingerprint() {
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a method to the list of dependent methods.
|
||||
*/
|
||||
public synchronized boolean addDependentMethod(CompiledMethodInfo cm) {
|
||||
return dependentMethods.add(cm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the array list of dependent class methods.
|
||||
*
|
||||
* @return array list of dependent methods
|
||||
*/
|
||||
public ArrayList<CompiledMethodInfo> getDependentMethods() {
|
||||
return dependentMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this class has dependent methods.
|
||||
*
|
||||
* @return true if dependent methods exist, false otherwise
|
||||
*/
|
||||
public boolean hasDependentMethods() {
|
||||
return !dependentMethods.isEmpty();
|
||||
}
|
||||
|
||||
public void setCompiledMethodsOffset(int offset) {
|
||||
compiledMethodsOffset = offset;
|
||||
}
|
||||
|
||||
protected void putAOTKlassData(BinaryContainer binaryContainer, ReadOnlyDataContainer container) {
|
||||
int cntDepMethods = dependentMethods.size();
|
||||
// Create array of dependent methods IDs. First word is count.
|
||||
ReadOnlyDataContainer dependenciesContainer = binaryContainer.getKlassesDependenciesContainer();
|
||||
this.dependentMethodsOffset = binaryContainer.addMethodsCount(cntDepMethods, dependenciesContainer);
|
||||
for (CompiledMethodInfo methodInfo : dependentMethods) {
|
||||
dependenciesContainer.appendInt(methodInfo.getCodeId());
|
||||
}
|
||||
verify();
|
||||
|
||||
// @formatter:off
|
||||
/*
|
||||
* The offsets layout should match AOTKlassData structure in AOT JVM runtime
|
||||
*/
|
||||
int offset = container.getByteStreamSize();
|
||||
container.createSymbol(offset, Kind.OBJECT, Binding.GLOBAL, 0, name);
|
||||
// Add index (offset/8) to the got in the .metaspace.got section
|
||||
container.appendInt(gotIndex).
|
||||
// Add unique ID
|
||||
appendInt(classId).
|
||||
// Add the offset to compiled methods data in the .metaspace.offsets section.
|
||||
appendInt(compiledMethodsOffset).
|
||||
// Add the offset to dependent methods data in the .metaspace.offsets section.
|
||||
appendInt(dependentMethodsOffset).
|
||||
// Add fingerprint.
|
||||
appendLong(fingerprint);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private void verify() {
|
||||
assert gotIndex > 0 : "incorrect gotIndex: " + gotIndex + " for klass: " + name;
|
||||
assert isArray || fingerprint != 0 : "incorrect fingerprint: " + fingerprint + " for klass: " + name;
|
||||
assert compiledMethodsOffset >= -1 : "incorrect compiledMethodsOffset: " + compiledMethodsOffset + " for klass: " + name;
|
||||
assert dependentMethodsOffset >= -1 : "incorrect dependentMethodsOffset: " + dependentMethodsOffset + " for klass: " + name;
|
||||
assert classId >= 0 : "incorrect classId: " + classId + " for klass: " + name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final HotSpotResolvedObjectType resolvedJavaType;
|
||||
|
||||
/**
|
||||
* List of all collected class data.
|
||||
*/
|
||||
private static Map<String, AOTKlassData> klassData = new HashMap<>();
|
||||
|
||||
/**
|
||||
* List of all methods to be compiled.
|
||||
*/
|
||||
private ArrayList<ResolvedJavaMethod> methods = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* List of all compiled class methods.
|
||||
*/
|
||||
private ArrayList<CompiledMethodInfo> compiledMethods;
|
||||
|
||||
/**
|
||||
* If this class represents Graal stub code.
|
||||
*/
|
||||
private final boolean representsStubs;
|
||||
|
||||
/**
|
||||
* Classes count used to generate unique global method id.
|
||||
*/
|
||||
private static int classesCount = 0;
|
||||
|
||||
/**
|
||||
* Construct an object with compiled methods. Intended to be used for code with no corresponding
|
||||
* Java method name in the user application.
|
||||
*
|
||||
* @param compiledMethods AOT compiled methods
|
||||
*/
|
||||
public AOTCompiledClass(ArrayList<CompiledMethodInfo> compiledMethods) {
|
||||
this.resolvedJavaType = null;
|
||||
this.compiledMethods = compiledMethods;
|
||||
this.representsStubs = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an object with compiled versions of the named class.
|
||||
*/
|
||||
public AOTCompiledClass(ResolvedJavaType resolvedJavaType) {
|
||||
this.resolvedJavaType = (HotSpotResolvedObjectType) resolvedJavaType;
|
||||
this.compiledMethods = new ArrayList<>();
|
||||
this.representsStubs = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ResolvedJavaType of this class
|
||||
*/
|
||||
public ResolvedJavaType getResolvedJavaType() {
|
||||
return resolvedJavaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of methods which should be compiled.
|
||||
*/
|
||||
public ArrayList<ResolvedJavaMethod> getMethods() {
|
||||
ArrayList<ResolvedJavaMethod> m = methods;
|
||||
methods = null; // Free - it is not used after that.
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of all AOT classes.
|
||||
*/
|
||||
public static int getClassesCount() {
|
||||
return classesCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of methods which should be compiled.
|
||||
*
|
||||
* @return number of methods which should be compiled
|
||||
*/
|
||||
public int getMethodCount() {
|
||||
return methods.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a method to the list of methods to be compiled.
|
||||
*/
|
||||
public void addMethod(ResolvedJavaMethod method) {
|
||||
methods.add(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this class has methods which should be compiled.
|
||||
*
|
||||
* @return true if this class contains methods which should be compiled, false otherwise
|
||||
*/
|
||||
public boolean hasMethods() {
|
||||
return !methods.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a method to the list of compiled methods. This method needs to be thread-safe.
|
||||
*/
|
||||
public synchronized boolean addCompiledMethod(CompiledMethodInfo cm) {
|
||||
return compiledMethods.add(cm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the array list of compiled class methods.
|
||||
*
|
||||
* @return array list of compiled methods
|
||||
*/
|
||||
public ArrayList<CompiledMethodInfo> getCompiledMethods() {
|
||||
return compiledMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this class has successfully compiled methods.
|
||||
*
|
||||
* @return true if methods were compiled, false otherwise
|
||||
*/
|
||||
public boolean hasCompiledMethods() {
|
||||
return !compiledMethods.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a klass data.
|
||||
*/
|
||||
public synchronized static AOTKlassData addAOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
|
||||
String name = type.getName();
|
||||
long fingerprint = type.getFingerprint();
|
||||
AOTKlassData data = klassData.get(name);
|
||||
if (data != null) {
|
||||
assert data.getFingerprint() == fingerprint : "incorrect fingerprint data for klass: " + name;
|
||||
} else {
|
||||
data = new AOTKlassData(binaryContainer, name, fingerprint, classesCount++);
|
||||
klassData.put(name, data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public synchronized static AOTKlassData getAOTKlassData(String name) {
|
||||
return klassData.get(name);
|
||||
}
|
||||
|
||||
public synchronized static AOTKlassData getAOTKlassData(HotSpotResolvedObjectType type) {
|
||||
return getAOTKlassData(type.getName());
|
||||
}
|
||||
|
||||
public void addAOTKlassData(BinaryContainer binaryContainer) {
|
||||
for (CompiledMethodInfo methodInfo : compiledMethods) {
|
||||
// Record methods holder
|
||||
methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType);
|
||||
// Record inlinee classes
|
||||
for (ResolvedJavaMethod m : methodInfo.getCompilationResult().getMethods()) {
|
||||
methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass());
|
||||
}
|
||||
// Record classes of fields that were accessed
|
||||
for (ResolvedJavaField f : methodInfo.getCompilationResult().getFields()) {
|
||||
methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static AOTKlassData addFingerprintKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
|
||||
if (type.isArray()) {
|
||||
return addAOTKlassData(binaryContainer, type);
|
||||
}
|
||||
assert type.getFingerprint() != 0 : "no fingerprint for " + type.getName();
|
||||
AOTKlassData old = getAOTKlassData(type);
|
||||
if (old != null) {
|
||||
boolean assertsEnabled = false;
|
||||
assert assertsEnabled = true;
|
||||
if (assertsEnabled) {
|
||||
HotSpotResolvedObjectType s = type.getSuperclass();
|
||||
if (s != null) {
|
||||
assert getAOTKlassData(s) != null : "fingerprint super " + s.getName() + " needed for " + type.getName();
|
||||
}
|
||||
for (HotSpotResolvedObjectType i : type.getInterfaces()) {
|
||||
assert getAOTKlassData(i) != null : "fingerprint super " + i.getName() + " needed for " + type.getName();
|
||||
}
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
// Fingerprinting requires super classes and super interfaces
|
||||
HotSpotResolvedObjectType s = type.getSuperclass();
|
||||
if (s != null) {
|
||||
addFingerprintKlassData(binaryContainer, s);
|
||||
}
|
||||
for (HotSpotResolvedObjectType i : type.getInterfaces()) {
|
||||
addFingerprintKlassData(binaryContainer, i);
|
||||
}
|
||||
|
||||
return addAOTKlassData(binaryContainer, type);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put methods data to contained.
|
||||
*/
|
||||
public void putMethodsData(BinaryContainer binaryContainer) {
|
||||
ReadOnlyDataContainer container = binaryContainer.getMethodsOffsetsContainer();
|
||||
int cntMethods = compiledMethods.size();
|
||||
int startMethods = binaryContainer.addMethodsCount(cntMethods, container);
|
||||
for (CompiledMethodInfo methodInfo : compiledMethods) {
|
||||
methodInfo.addMethodOffsets(binaryContainer, container);
|
||||
}
|
||||
String name = resolvedJavaType.getName();
|
||||
AOTKlassData data = klassData.get(name);
|
||||
assert data != null : "missing data for klass: " + name;
|
||||
assert data.getFingerprint() == resolvedJavaType.getFingerprint() : "incorrect fingerprint for klass: " + name;
|
||||
int cntDepMethods = data.dependentMethods.size();
|
||||
assert cntDepMethods > 0 : "no dependent methods for compiled klass: " + name;
|
||||
data.setCompiledMethodsOffset(startMethods);
|
||||
}
|
||||
|
||||
public static void putAOTKlassData(BinaryContainer binaryContainer) {
|
||||
ReadOnlyDataContainer container = binaryContainer.getKlassesOffsetsContainer();
|
||||
for (AOTKlassData data : klassData.values()) {
|
||||
data.putAOTKlassData(binaryContainer, container);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean representsStubs() {
|
||||
return representsStubs;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
for (CompiledMethodInfo c : compiledMethods) {
|
||||
c.clear();
|
||||
}
|
||||
this.compiledMethods = null;
|
||||
this.methods = null;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.PriorityBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
public class AOTCompiler {
|
||||
|
||||
private final Main main;
|
||||
|
||||
private CompileQueue compileQueue;
|
||||
|
||||
private final AOTBackend backend;
|
||||
|
||||
/**
|
||||
* Compile queue.
|
||||
*/
|
||||
private class CompileQueue extends ThreadPoolExecutor {
|
||||
|
||||
/**
|
||||
* Time of the start of this queue.
|
||||
*/
|
||||
private final long startTime;
|
||||
|
||||
/**
|
||||
* Method counter for successful compilations.
|
||||
*/
|
||||
private final AtomicInteger successfulMethodCount = new AtomicInteger();
|
||||
|
||||
/**
|
||||
* Method counter for failed compilations.
|
||||
*/
|
||||
private final AtomicInteger failedMethodCount = new AtomicInteger();
|
||||
|
||||
/**
|
||||
* Create a compile queue with the given number of threads.
|
||||
*/
|
||||
public CompileQueue(final int threads) {
|
||||
super(threads, threads, 0L, TimeUnit.MILLISECONDS, new PriorityBlockingQueue<>());
|
||||
startTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterExecute(Runnable r, Throwable t) {
|
||||
AOTCompilationTask task = (AOTCompilationTask) r;
|
||||
if (task.getResult() != null) {
|
||||
final int count = successfulMethodCount.incrementAndGet();
|
||||
if (count % 100 == 0) {
|
||||
main.printInfo(".");
|
||||
}
|
||||
CompiledMethodInfo result = task.getResult();
|
||||
if (result != null) {
|
||||
task.getHolder().addCompiledMethod(result);
|
||||
}
|
||||
} else {
|
||||
failedMethodCount.incrementAndGet();
|
||||
main.printlnVerbose("");
|
||||
ResolvedJavaMethod method = task.getMethod();
|
||||
main.printlnVerbose(" failed " + method.getName() + method.getSignature().toMethodDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void terminated() {
|
||||
final long endTime = System.currentTimeMillis();
|
||||
final int success = successfulMethodCount.get();
|
||||
final int failed = failedMethodCount.get();
|
||||
main.printlnInfo("");
|
||||
main.printlnInfo(success + " methods compiled, " + failed + " methods failed (" + (endTime - startTime) + " ms)");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param main
|
||||
* @param aotBackend
|
||||
* @param threads number of compilation threads
|
||||
*/
|
||||
public AOTCompiler(Main main, AOTBackend aotBackend, final int threads) {
|
||||
this.main = main;
|
||||
this.compileQueue = new CompileQueue(threads);
|
||||
this.backend = aotBackend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile all methods in all classes passed.
|
||||
*
|
||||
* @param classes a list of class to compile
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public List<AOTCompiledClass> compileClasses(List<AOTCompiledClass> classes) throws InterruptedException {
|
||||
main.printlnInfo("Compiling with " + compileQueue.getCorePoolSize() + " threads");
|
||||
main.printInfo("."); // Compilation progress indication.
|
||||
|
||||
for (AOTCompiledClass c : classes) {
|
||||
for (ResolvedJavaMethod m : c.getMethods()) {
|
||||
enqueueMethod(c, m);
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown queue and wait for all tasks to complete.
|
||||
compileQueue.shutdown();
|
||||
compileQueue.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
|
||||
|
||||
List<AOTCompiledClass> compiledClasses = new ArrayList<>();
|
||||
for (AOTCompiledClass compiledClass : classes) {
|
||||
if (compiledClass.hasCompiledMethods()) {
|
||||
compiledClasses.add(compiledClass);
|
||||
}
|
||||
}
|
||||
return compiledClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue a method in the {@link #compileQueue}.
|
||||
*
|
||||
* @param method method to be enqueued
|
||||
*/
|
||||
private void enqueueMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method) {
|
||||
AOTCompilationTask task = new AOTCompilationTask(main, aotClass, method, backend);
|
||||
try {
|
||||
compileQueue.execute(task);
|
||||
} catch (RejectedExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void logCompilation(String methodName, String message) {
|
||||
Main.writeLog(message + " " + methodName);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc;
|
||||
|
||||
import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
|
||||
import jdk.vm.ci.hotspot.HotSpotCompiledCode;
|
||||
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
|
||||
|
||||
public class AOTHotSpotResolvedJavaMethod implements JavaMethodInfo {
|
||||
|
||||
private final HotSpotResolvedJavaMethod method;
|
||||
|
||||
public AOTHotSpotResolvedJavaMethod(HotSpotResolvedJavaMethod method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public String getSymbolName() {
|
||||
return MiscUtils.uniqueMethodName(method);
|
||||
}
|
||||
|
||||
public String getNameAndSignature() {
|
||||
String className = method.getDeclaringClass().getName();
|
||||
return className + "." + method.getName() + method.getSignature().toMethodDescriptor();
|
||||
}
|
||||
|
||||
public HotSpotCompiledCode compiledCode(CompilationResult result) {
|
||||
return HotSpotCompiledCodeBuilder.createCompiledCode(method, null, result);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user