diff --git a/.hgignore b/.hgignore index 9aab81ce35d..023de87e688 100644 --- a/.hgignore +++ b/.hgignore @@ -3,8 +3,7 @@ ^.idea/ nbproject/private/ ^webrev -^.hgtip -^.bridge2 +^.src-rev$ ^.jib/ .DS_Store .metadata/ diff --git a/.hgtags b/.hgtags index f54925473b1..cc1f425ff14 100644 --- a/.hgtags +++ b/.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 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 846b6a11335..cb9368a1832 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -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 diff --git a/common/autoconf/basics.m4 b/common/autoconf/basics.m4 index 7f8c42f6b98..9d5789e37ca 100644 --- a/common/autoconf/basics.m4 +++ b/common/autoconf/basics.m4 @@ -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 diff --git a/common/autoconf/boot-jdk.m4 b/common/autoconf/boot-jdk.m4 index ab2bd9a87d7..f75f3adfa2a 100644 --- a/common/autoconf/boot-jdk.m4 +++ b/common/autoconf/boot-jdk.m4 @@ -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 diff --git a/common/autoconf/build-performance.m4 b/common/autoconf/build-performance.m4 index 863875065a6..fd77fe8c2b0 100644 --- a/common/autoconf/build-performance.m4 +++ b/common/autoconf/build-performance.m4 @@ -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]$'`] diff --git a/common/autoconf/buildjdk-spec.gmk.in b/common/autoconf/buildjdk-spec.gmk.in index dba07605a22..ddd388c0f1c 100644 --- a/common/autoconf/buildjdk-spec.gmk.in +++ b/common/autoconf/buildjdk-spec.gmk.in @@ -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 diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac index bb5491ba0b4..4879d05622b 100644 --- a/common/autoconf/configure.ac +++ b/common/autoconf/configure.ac @@ -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. diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index eb912119e70..767f6bed510 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -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]) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 131556f50ad..79ef6b5bfca 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -671,6 +671,8 @@ LLVM_LIBS LLVM_LDFLAGS LLVM_CFLAGS LLVM_CONFIG +LIBFFI_LIB_FILE +ENABLE_LIBFFI_BUNDLING LIBFFI_LIBS LIBFFI_CFLAGS ALSA_LIBS @@ -700,8 +702,6 @@ JVM_FEATURES_client JVM_FEATURES_server INCLUDE_DTRACE GCOV_ENABLED -STRIP_POLICY -DEBUG_BINARIES ZIP_EXTERNAL_DEBUG_SYMBOLS COPY_DEBUG_SYMBOLS COMPILE_WITH_DEBUG_SYMBOLS @@ -791,11 +791,6 @@ JTREGEXE HOTSPOT_TOOLCHAIN_TYPE USING_BROKEN_SUSE_LD PACKAGE_PATH -USE_CLANG -HOTSPOT_LD -HOTSPOT_CXX -HOTSPOT_RC -HOTSPOT_MT BUILD_AS BUILD_LDCXX BUILD_LD @@ -945,7 +940,7 @@ HG READELF OTOOL LDD -ZIP +ZIPEXE UNZIP TAR_SUPPORTS_TRANSFORM TAR_INCLUDE_PARAM @@ -1215,6 +1210,7 @@ with_alsa_lib with_libffi with_libffi_include with_libffi_lib +enable_libffi_bundling with_libjpeg with_giflib with_libpng @@ -1292,7 +1288,7 @@ CPIO NICE MAKE UNZIP -ZIP +ZIPEXE LDD OTOOL READELF @@ -1974,8 +1970,8 @@ Optional Features: --enable-debug set the debug level to fastdebug (shorthand for --with-debug-level=fastdebug) [disabled] --enable-headless-only only build headless (no GUI) support [disabled] - --enable-unlimited-crypto - Enable unlimited crypto policy [disabled] + --disable-unlimited-crypto + Disable unlimited crypto policy [enabled] --disable-keep-packaged-modules Do not keep packaged modules in jdk image [enable] --enable-static-build enable static library build [disabled] @@ -1997,6 +1993,9 @@ Optional Features: disable bundling of the freetype library with the build result [enabled on Windows or when using --with-freetype, disabled otherwise] + --enable-libffi-bundling + enable bundling of libffi.so to make the built JDK + runnable on more systems --enable-jtreg-failure-handler forces build of the jtreg failure handler to be enabled, missing dependencies become fatal errors. @@ -2236,7 +2235,7 @@ Some influential environment variables: NICE Override default value for NICE MAKE Override default value for MAKE UNZIP Override default value for UNZIP - ZIP Override default value for ZIP + ZIPEXE Override default value for ZIPEXE LDD Override default value for LDD OTOOL Override default value for OTOOL READELF Override default value for READELF @@ -3851,7 +3850,7 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # $1 A command line (typically autoconf macro) to execute -# Test: Is bootjdk explicitely set by command line arguments? +# Test: Is bootjdk explicitly set by command line arguments? # Test: Is $JAVA_HOME set? @@ -4178,7 +4177,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) @@ -4911,7 +4910,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="" @@ -4982,10 +4981,6 @@ TOOLCHAIN_MINIMUM_VERSION_xlc="" # for this, we can only do this after these have been setup. -# Setup legacy variables that are still needed as alternative ways to refer to -# parts of the toolchain. - - # Do some additional checks on the detected tools. @@ -5093,7 +5088,7 @@ VS_SDK_PLATFORM_NAME_2013= #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1478524503 +DATE_WHEN_GENERATED=1481104795 ############################################################################### # @@ -15523,7 +15518,7 @@ test -n "$target_alias" && ;; esac - # ..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" @@ -15662,7 +15657,7 @@ $as_echo "$OPENJDK_BUILD_OS-$OPENJDK_BUILD_CPU" >&6; } ;; esac - # ... 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" @@ -21373,13 +21368,15 @@ $as_echo "$tool_specified" >&6; } fi + # Since zip uses "ZIP" as a environment variable for passing options, we need + # to name our variable differently, hence ZIPEXE. # Publish this variable in the help. - if [ -z "${ZIP+x}" ]; then + if [ -z "${ZIPEXE+x}" ]; then # The variable is not set by user, try to locate tool using the code snippet for ac_prog in zip do @@ -21387,12 +21384,12 @@ do set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ZIP+:} false; then : +if ${ac_cv_path_ZIPEXE+:} false; then : $as_echo_n "(cached) " >&6 else - case $ZIP in + case $ZIPEXE in [\\/]* | ?:[\\/]*) - ac_cv_path_ZIP="$ZIP" # Let the user override the test with a path. + ac_cv_path_ZIPEXE="$ZIPEXE" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -21402,7 +21399,7 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ZIP="$as_dir/$ac_word$ac_exec_ext" + ac_cv_path_ZIPEXE="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -21413,30 +21410,30 @@ IFS=$as_save_IFS ;; esac fi -ZIP=$ac_cv_path_ZIP -if test -n "$ZIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ZIP" >&5 -$as_echo "$ZIP" >&6; } +ZIPEXE=$ac_cv_path_ZIPEXE +if test -n "$ZIPEXE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ZIPEXE" >&5 +$as_echo "$ZIPEXE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi - test -n "$ZIP" && break + test -n "$ZIPEXE" && break done else # The variable is set, but is it from the command line or the environment? - # Try to remove the string !ZIP! from our list. - try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!ZIP!/} + # Try to remove the string !ZIPEXE! from our list. + try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!ZIPEXE!/} if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then # If it failed, the variable was not from the command line. Ignore it, # but warn the user (except for BASH, which is always set by the calling BASH). - if test "xZIP" != xBASH; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of ZIP from the environment. Use command line variables instead." >&5 -$as_echo "$as_me: WARNING: Ignoring value of ZIP from the environment. Use command line variables instead." >&2;} + if test "xZIPEXE" != xBASH; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of ZIPEXE from the environment. Use command line variables instead." >&5 +$as_echo "$as_me: WARNING: Ignoring value of ZIPEXE from the environment. Use command line variables instead." >&2;} fi # Try to locate tool using the code snippet for ac_prog in zip @@ -21445,12 +21442,12 @@ do set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ZIP+:} false; then : +if ${ac_cv_path_ZIPEXE+:} false; then : $as_echo_n "(cached) " >&6 else - case $ZIP in + case $ZIPEXE in [\\/]* | ?:[\\/]*) - ac_cv_path_ZIP="$ZIP" # Let the user override the test with a path. + ac_cv_path_ZIPEXE="$ZIPEXE" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -21460,7 +21457,7 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ZIP="$as_dir/$ac_word$ac_exec_ext" + ac_cv_path_ZIPEXE="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -21471,17 +21468,17 @@ IFS=$as_save_IFS ;; esac fi -ZIP=$ac_cv_path_ZIP -if test -n "$ZIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ZIP" >&5 -$as_echo "$ZIP" >&6; } +ZIPEXE=$ac_cv_path_ZIPEXE +if test -n "$ZIPEXE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ZIPEXE" >&5 +$as_echo "$ZIPEXE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi - test -n "$ZIP" && break + test -n "$ZIPEXE" && break done else @@ -21493,31 +21490,31 @@ done CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var" # Check if we try to supply an empty value - if test "x$ZIP" = x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: Setting user supplied tool ZIP= (no value)" >&5 -$as_echo "$as_me: Setting user supplied tool ZIP= (no value)" >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ZIP" >&5 -$as_echo_n "checking for ZIP... " >&6; } + if test "x$ZIPEXE" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Setting user supplied tool ZIPEXE= (no value)" >&5 +$as_echo "$as_me: Setting user supplied tool ZIPEXE= (no value)" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ZIPEXE" >&5 +$as_echo_n "checking for ZIPEXE... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } else # Check if the provided tool contains a complete path. - tool_specified="$ZIP" + tool_specified="$ZIPEXE" tool_basename="${tool_specified##*/}" if test "x$tool_basename" = "x$tool_specified"; then # A command without a complete path is provided, search $PATH. - { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool ZIP=$tool_basename" >&5 -$as_echo "$as_me: Will search for user supplied tool ZIP=$tool_basename" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool ZIPEXE=$tool_basename" >&5 +$as_echo "$as_me: Will search for user supplied tool ZIPEXE=$tool_basename" >&6;} # Extract the first word of "$tool_basename", so it can be a program name with args. set dummy $tool_basename; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ZIP+:} false; then : +if ${ac_cv_path_ZIPEXE+:} false; then : $as_echo_n "(cached) " >&6 else - case $ZIP in + case $ZIPEXE in [\\/]* | ?:[\\/]*) - ac_cv_path_ZIP="$ZIP" # Let the user override the test with a path. + ac_cv_path_ZIPEXE="$ZIPEXE" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -21527,7 +21524,7 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ZIP="$as_dir/$ac_word$ac_exec_ext" + ac_cv_path_ZIPEXE="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -21538,29 +21535,29 @@ IFS=$as_save_IFS ;; esac fi -ZIP=$ac_cv_path_ZIP -if test -n "$ZIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ZIP" >&5 -$as_echo "$ZIP" >&6; } +ZIPEXE=$ac_cv_path_ZIPEXE +if test -n "$ZIPEXE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ZIPEXE" >&5 +$as_echo "$ZIPEXE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi - if test "x$ZIP" = x; then + if test "x$ZIPEXE" = x; then as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5 fi else # Otherwise we believe it is a complete path. Use it as it is. - { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool ZIP=$tool_specified" >&5 -$as_echo "$as_me: Will use user supplied tool ZIP=$tool_specified" >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ZIP" >&5 -$as_echo_n "checking for ZIP... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool ZIPEXE=$tool_specified" >&5 +$as_echo "$as_me: Will use user supplied tool ZIPEXE=$tool_specified" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ZIPEXE" >&5 +$as_echo_n "checking for ZIPEXE... " >&6; } if test ! -x "$tool_specified"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } - as_fn_error $? "User supplied tool ZIP=$tool_specified does not exist or is not executable" "$LINENO" 5 + as_fn_error $? "User supplied tool ZIPEXE=$tool_specified does not exist or is not executable" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5 $as_echo "$tool_specified" >&6; } @@ -21572,8 +21569,8 @@ $as_echo "$tool_specified" >&6; } - if test "x$ZIP" = x; then - as_fn_error $? "Could not find required tool for ZIP" "$LINENO" 5 + if test "x$ZIPEXE" = x; then + as_fn_error $? "Could not find required tool for ZIPEXE" "$LINENO" 5 fi @@ -24238,7 +24235,7 @@ fi if test "${enable_unlimited_crypto+set}" = set; then : enableval=$enable_unlimited_crypto; else - enable_unlimited_crypto=no + enable_unlimited_crypto=yes fi if test "x$enable_unlimited_crypto" = "xyes"; then @@ -24398,7 +24395,7 @@ fi as_fn_error $? "Version string contains + but both 'BUILD' and 'OPT' are missing" "$LINENO" 5 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 as_fn_error $? "--with-version-string fails to parse as a valid version string: $with_version_string" "$LINENO" 5 @@ -24460,11 +24457,10 @@ $as_echo "$as_me: WARNING: --with-version-opt value has been sanitized from '$wi fi else if test "x$NO_DEFAULT_VERSION_PARTS" != xtrue; then - # Default is to calculate a string like this .. - timestamp=`$DATE '+%Y-%m-%d-%H%M%S'` + # Default is to calculate a string like this 'adhoc..' # 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 @@ -24767,7 +24763,7 @@ fi # 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? if test "x$BOOT_JDK_FOUND" = xno; then # Now execute the test @@ -29885,8 +29881,8 @@ $as_echo "$BOOT_JDK_VERSION" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find a valid Boot JDK. $HELP_MSG" >&5 $as_echo "$as_me: Could not find a valid Boot JDK. $HELP_MSG" >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: This might be fixed by explicitely setting --with-boot-jdk" >&5 -$as_echo "$as_me: This might be fixed by explicitely setting --with-boot-jdk" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: This might be fixed by explicitly setting --with-boot-jdk" >&5 +$as_echo "$as_me: This might be fixed by explicitly setting --with-boot-jdk" >&6;} as_fn_error $? "Cannot continue" "$LINENO" 5 fi @@ -29908,8 +29904,8 @@ $as_echo_n "checking for java in Boot JDK... " >&6; } if test ! -x $JAVA; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5 -$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5 +$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;} as_fn_error $? "Could not find java in the Boot JDK" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 @@ -29936,8 +29932,8 @@ $as_echo_n "checking for java in Boot JDK... " >&6; } if test ! -x $JAVA; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5 -$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5 +$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;} as_fn_error $? "Could not find java in the Boot JDK" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 @@ -30046,8 +30042,8 @@ $as_echo_n "checking for javac in Boot JDK... " >&6; } if test ! -x $JAVAC; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5 -$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5 +$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;} as_fn_error $? "Could not find javac in the Boot JDK" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 @@ -30074,8 +30070,8 @@ $as_echo_n "checking for javac in Boot JDK... " >&6; } if test ! -x $JAVAC; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5 -$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5 +$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;} as_fn_error $? "Could not find javac in the Boot JDK" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 @@ -30184,8 +30180,8 @@ $as_echo_n "checking for javah in Boot JDK... " >&6; } if test ! -x $JAVAH; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5 -$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5 +$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;} as_fn_error $? "Could not find javah in the Boot JDK" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 @@ -30212,8 +30208,8 @@ $as_echo_n "checking for javah in Boot JDK... " >&6; } if test ! -x $JAVAH; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5 -$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5 +$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;} as_fn_error $? "Could not find javah in the Boot JDK" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 @@ -30322,8 +30318,8 @@ $as_echo_n "checking for jar in Boot JDK... " >&6; } if test ! -x $JAR; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5 -$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5 +$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;} as_fn_error $? "Could not find jar in the Boot JDK" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 @@ -30350,8 +30346,8 @@ $as_echo_n "checking for jar in Boot JDK... " >&6; } if test ! -x $JAR; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5 -$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5 +$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;} as_fn_error $? "Could not find jar in the Boot JDK" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 @@ -30460,8 +30456,8 @@ $as_echo_n "checking for jarsigner in Boot JDK... " >&6; } if test ! -x $JARSIGNER; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5 -$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5 +$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;} as_fn_error $? "Could not find jarsigner in the Boot JDK" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 @@ -30488,8 +30484,8 @@ $as_echo_n "checking for jarsigner in Boot JDK... " >&6; } if test ! -x $JARSIGNER; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5 -$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5 +$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;} as_fn_error $? "Could not find jarsigner in the Boot JDK" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 @@ -31196,6 +31192,12 @@ $as_echo "$as_me: The path of IMPORT_MODULES_TOPDIR, which resolves as \"$path\" 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 @@ -33576,9 +33578,11 @@ $as_echo "$as_me: Please use --enable-ccache instead of providing a wrapped comp 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` { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 @@ -34873,9 +34877,11 @@ $as_echo "$as_me: Please use --enable-ccache instead of providing a wrapped comp 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` { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 @@ -35259,9 +35265,9 @@ $as_echo "$as_me: WARNING: This typically indicates a broken setup, and is not s fi # We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal. - if [[ "[$]CC_VERSION_NUMBER" =~ (.*\.){3} ]] ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than three parts (X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&5 -$as_echo "$as_me: WARNING: C compiler version number has more than three parts (X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;} + if [[ "[$]CC_VERSION_NUMBER" =~ (.*\.){4} ]] ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than four parts (W.X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&5 +$as_echo "$as_me: WARNING: C compiler version number has more than four parts (W.X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;} fi if [[ "[$]CC_VERSION_NUMBER" =~ [0-9]{6} ]] ; then @@ -35269,7 +35275,7 @@ $as_echo "$as_me: WARNING: C compiler version number has more than three parts ( $as_echo "$as_me: WARNING: C compiler version number has a part larger than 99999: $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;} fi - COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$CC_VERSION_NUMBER"` + COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", $1, $2, $3, $4) }' <<< "$CC_VERSION_NUMBER"` if test "x$TOOLCHAIN_MINIMUM_VERSION" != x; then @@ -35327,8 +35333,8 @@ $as_echo "$as_me: WARNING: C compiler version number has a part larger than 9999 # Need to assign to a variable since m4 is blocked from modifying parts in []. REFERENCE_VERSION=$TOOLCHAIN_MINIMUM_VERSION - if [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ; then - as_fn_error $? "Internal error: Cannot compare to $TOOLCHAIN_MINIMUM_VERSION, only three parts (X.Y.Z) is supported" "$LINENO" 5 + if [[ "$REFERENCE_VERSION" =~ (.*\.){4} ]] ; then + as_fn_error $? "Internal error: Cannot compare to $TOOLCHAIN_MINIMUM_VERSION, only four parts (W.X.Y.Z) is supported" "$LINENO" 5 fi if [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ; then @@ -35336,7 +35342,7 @@ $as_echo "$as_me: WARNING: C compiler version number has a part larger than 9999 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 $COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then : @@ -46954,9 +46960,11 @@ $as_echo "$as_me: Rewriting BUILD_STRIP to \"$new_complete\"" >&6;} 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` { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 @@ -47074,9 +47082,11 @@ $as_echo "$as_me: Using $TOOLCHAIN_TYPE $COMPILER_NAME compiler version $COMPILE 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` { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5 @@ -47196,9 +47206,9 @@ $as_echo "$as_me: WARNING: This typically indicates a broken setup, and is not s fi # We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal. - if [[ "[$]BUILD_CC_VERSION_NUMBER" =~ (.*\.){3} ]] ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than three parts (X.Y.Z): $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&5 -$as_echo "$as_me: WARNING: C compiler version number has more than three parts (X.Y.Z): $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&2;} + if [[ "[$]BUILD_CC_VERSION_NUMBER" =~ (.*\.){4} ]] ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than four parts (W.X.Y.Z): $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&5 +$as_echo "$as_me: WARNING: C compiler version number has more than four parts (W.X.Y.Z): $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&2;} fi if [[ "[$]BUILD_CC_VERSION_NUMBER" =~ [0-9]{6} ]] ; then @@ -47206,7 +47216,7 @@ $as_echo "$as_me: WARNING: C compiler version number has more than three parts ( $as_echo "$as_me: WARNING: C compiler version number has a part larger than 99999: $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&2;} fi - OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$BUILD_CC_VERSION_NUMBER"` + OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", $1, $2, $3, $4) }' <<< "$BUILD_CC_VERSION_NUMBER"` else # If we are not cross compiling, use the normal target compilers for @@ -47232,9 +47242,9 @@ $as_echo "$as_me: WARNING: This typically indicates a broken setup, and is not s fi # We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal. - if [[ "[$]CC_VERSION_NUMBER" =~ (.*\.){3} ]] ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than three parts (X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&5 -$as_echo "$as_me: WARNING: C compiler version number has more than three parts (X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;} + if [[ "[$]CC_VERSION_NUMBER" =~ (.*\.){4} ]] ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than four parts (W.X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&5 +$as_echo "$as_me: WARNING: C compiler version number has more than four parts (W.X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;} fi if [[ "[$]CC_VERSION_NUMBER" =~ [0-9]{6} ]] ; then @@ -47242,7 +47252,7 @@ $as_echo "$as_me: WARNING: C compiler version number has more than three parts ( $as_echo "$as_me: WARNING: C compiler version number has a part larger than 99999: $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;} fi - OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$CC_VERSION_NUMBER"` + OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", $1, $2, $3, $4) }' <<< "$CC_VERSION_NUMBER"` fi @@ -47257,68 +47267,6 @@ $as_echo "$as_me: WARNING: C compiler version number has a part larger than 9999 - 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" - - unix_path="$HOTSPOT_CXX" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - windows_path=`$CYGPATH -m "$unix_path"` - HOTSPOT_CXX="$windows_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - windows_path=`cmd //c echo $unix_path` - HOTSPOT_CXX="$windows_path" - fi - - - unix_path="$HOTSPOT_LD" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - windows_path=`$CYGPATH -m "$unix_path"` - HOTSPOT_LD="$windows_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - windows_path=`cmd //c echo $unix_path` - HOTSPOT_LD="$windows_path" - fi - - - unix_path="$HOTSPOT_MT" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - windows_path=`$CYGPATH -m "$unix_path"` - HOTSPOT_MT="$windows_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - windows_path=`cmd //c echo $unix_path` - HOTSPOT_MT="$windows_path" - fi - - - unix_path="$HOTSPOT_RC" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - windows_path=`$CYGPATH -m "$unix_path"` - HOTSPOT_RC="$windows_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - windows_path=`cmd //c echo $unix_path` - HOTSPOT_RC="$windows_path" - fi - - - - else - HOTSPOT_CXX="$CXX" - HOTSPOT_LD="$LD" - fi - - - - if test "x$TOOLCHAIN_TYPE" = xclang; then - USE_CLANG=true - fi - - - # The package path is used only on macosx? @@ -49101,7 +49049,11 @@ $as_echo "$ac_cv_c_bigendian" >&6; } 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" @@ -49908,8 +49860,8 @@ $as_echo "$supports" >&6; } # Need to assign to a variable since m4 is blocked from modifying parts in []. REFERENCE_VERSION=6 - if [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ; then - as_fn_error $? "Internal error: Cannot compare to 6, only three parts (X.Y.Z) is supported" "$LINENO" 5 + if [[ "$REFERENCE_VERSION" =~ (.*\.){4} ]] ; then + as_fn_error $? "Internal error: Cannot compare to 6, only four parts (W.X.Y.Z) is supported" "$LINENO" 5 fi if [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ; then @@ -49917,7 +49869,7 @@ $as_echo "$supports" >&6; } 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 $COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then : @@ -50020,7 +49972,6 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA fastdebug | slowdebug ) CFLAGS_JDK="$CFLAGS_JDK $CFLAGS_DEBUG_SYMBOLS $CFLAGS_DEBUG_OPTIONS" CXXFLAGS_JDK="$CXXFLAGS_JDK $CXXFLAGS_DEBUG_SYMBOLS $CXXFLAGS_DEBUG_OPTIONS" - JAVAC_FLAGS="$JAVAC_FLAGS -g" ;; release ) ;; @@ -50076,12 +50027,12 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA # Set some additional per-OS defines. if test "x$OPENJDK_TARGET_OS" = xlinux; then JVM_CFLAGS="$JVM_CFLAGS -DLINUX" - JVM_CFLAGS="$JVM_CFLAGS -pipe -fPIC -fno-rtti -fno-exceptions \ + JVM_CFLAGS="$JVM_CFLAGS -pipe $PICFLAG -fno-rtti -fno-exceptions \ -fvisibility=hidden -fno-strict-aliasing -fno-omit-frame-pointer" elif test "x$OPENJDK_TARGET_OS" = xsolaris; then JVM_CFLAGS="$JVM_CFLAGS -DSOLARIS" JVM_CFLAGS="$JVM_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_TARGET_OS" = xmacosx; then COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D_ALLBSD_SOURCE -D_DARWIN_UNLIMITED_SELECT" JVM_CFLAGS="$JVM_CFLAGS -D_ALLBSD_SOURCE" @@ -50124,7 +50075,7 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA # Little endian machine uses ELFv2 ABI. JVM_CFLAGS="$JVM_CFLAGS -DABI_ELFv2" # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. - JVM_CFLAGS="$JVM_CFLAGS -mcpu=power7 -mtune=power8" + JVM_CFLAGS="$JVM_CFLAGS -mcpu=power8 -mtune=power8" fi elif test "x$OPENJDK_TARGET_CPU" = xs390x; then if test "x$OPENJDK_TARGET_OS" = xlinux; then @@ -50209,8 +50160,8 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA # Need to assign to a variable since m4 is blocked from modifying parts in []. REFERENCE_VERSION=4.8 - if [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ; then - as_fn_error $? "Internal error: Cannot compare to 4.8, only three parts (X.Y.Z) is supported" "$LINENO" 5 + if [[ "$REFERENCE_VERSION" =~ (.*\.){4} ]] ; then + as_fn_error $? "Internal error: Cannot compare to 4.8, only four parts (W.X.Y.Z) is supported" "$LINENO" 5 fi if [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ; then @@ -50218,7 +50169,7 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA 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 $COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then : @@ -50732,8 +50683,8 @@ $as_echo "$supports" >&6; } # Need to assign to a variable since m4 is blocked from modifying parts in []. REFERENCE_VERSION=6 - if [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ; then - as_fn_error $? "Internal error: Cannot compare to 6, only three parts (X.Y.Z) is supported" "$LINENO" 5 + if [[ "$REFERENCE_VERSION" =~ (.*\.){4} ]] ; then + as_fn_error $? "Internal error: Cannot compare to 6, only four parts (W.X.Y.Z) is supported" "$LINENO" 5 fi if [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ; then @@ -50741,7 +50692,7 @@ $as_echo "$supports" >&6; } 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 $OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then : @@ -50844,7 +50795,6 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA fastdebug | slowdebug ) OPENJDK_BUILD_CFLAGS_JDK="$OPENJDK_BUILD_CFLAGS_JDK $CFLAGS_DEBUG_SYMBOLS $CFLAGS_DEBUG_OPTIONS" OPENJDK_BUILD_CXXFLAGS_JDK="$OPENJDK_BUILD_CXXFLAGS_JDK $CXXFLAGS_DEBUG_SYMBOLS $CXXFLAGS_DEBUG_OPTIONS" - JAVAC_FLAGS="$JAVAC_FLAGS -g" ;; release ) ;; @@ -50900,12 +50850,12 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA # Set some additional per-OS defines. if test "x$OPENJDK_BUILD_OS" = xlinux; then OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -DLINUX" - OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -pipe -fPIC -fno-rtti -fno-exceptions \ + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -pipe $PICFLAG -fno-rtti -fno-exceptions \ -fvisibility=hidden -fno-strict-aliasing -fno-omit-frame-pointer" elif test "x$OPENJDK_BUILD_OS" = xsolaris; then OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -DSOLARIS" OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_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_BUILD_OS" = xmacosx; then OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -D_ALLBSD_SOURCE -D_DARWIN_UNLIMITED_SELECT" OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -D_ALLBSD_SOURCE" @@ -50948,7 +50898,7 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA # Little endian machine uses ELFv2 ABI. OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -DABI_ELFv2" # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. - OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -mcpu=power7 -mtune=power8" + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -mcpu=power8 -mtune=power8" fi elif test "x$OPENJDK_BUILD_CPU" = xs390x; then if test "x$OPENJDK_BUILD_OS" = xlinux; then @@ -51033,8 +50983,8 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA # Need to assign to a variable since m4 is blocked from modifying parts in []. REFERENCE_VERSION=4.8 - if [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ; then - as_fn_error $? "Internal error: Cannot compare to 4.8, only three parts (X.Y.Z) is supported" "$LINENO" 5 + if [[ "$REFERENCE_VERSION" =~ (.*\.){4} ]] ; then + as_fn_error $? "Internal error: Cannot compare to 4.8, only four parts (W.X.Y.Z) is supported" "$LINENO" 5 fi if [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ; then @@ -51042,7 +50992,7 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA 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 $OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then : @@ -51913,8 +51863,8 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if native warnings are errors" >&5 $as_echo_n "checking if native warnings are errors... " >&6; } if test "x$enable_warnings_as_errors" = "xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (explicitely set)" >&5 -$as_echo "yes (explicitely set)" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (explicitly set)" >&5 +$as_echo "yes (explicitly set)" >&6; } WARNINGS_AS_ERRORS=true elif test "x$enable_warnings_as_errors" = "xno"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 @@ -52579,28 +52529,14 @@ $as_echo "$NATIVE_DEBUG_SYMBOLS" >&6; } 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 @@ -52614,10 +52550,6 @@ $as_echo "$NATIVE_DEBUG_SYMBOLS" >&6; } 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 as_fn_error $? "Allowed native debug symbols are: none, internal, external, zipped" "$LINENO" 5 fi @@ -52666,10 +52598,6 @@ $as_echo "$as_me: WARNING: Please use --with-native-debug-symbols=zipped ." >&2; - # Legacy values - - - # Check whether --enable-native-coverage was given. if test "${enable_native_coverage+set}" = set; then : @@ -53191,7 +53119,7 @@ fi 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. DLL_NAME="$MSVCR_NAME" POSSIBLE_MSVC_DLL="$with_msvcr_dll" @@ -54540,7 +54468,7 @@ fi 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. DLL_NAME="$MSVCP_NAME" POSSIBLE_MSVC_DLL="$with_msvcp_dll" @@ -55899,7 +55827,7 @@ $as_echo "$as_me: WARNING: X11 is not used, so --with-x is ignored" >&2;} 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 @@ -62711,6 +62639,11 @@ if test "${with_libffi_lib+set}" = set; then : withval=$with_libffi_lib; fi + # Check whether --enable-libffi-bundling was given. +if test "${enable_libffi_bundling+set}" = set; then : + enableval=$enable_libffi_bundling; +fi + if test "x$NEEDS_LIB_FFI" = xfalse; then if (test "x${with_libffi}" != x && test "x${with_libffi}" != xno) || \ @@ -62729,6 +62662,7 @@ $as_echo "$as_me: WARNING: libffi not used, so --with-libffi[-*] is ignored" >&2 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 @@ -62738,6 +62672,7 @@ $as_echo "$as_me: WARNING: libffi not used, so --with-libffi[-*] is ignored" >&2 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 @@ -62947,12 +62882,75 @@ $as_echo "$LIBFFI_WORKS" >&6; } as_fn_error $? "Found libffi but could not link and compile with it. $HELP_MSG" "$LINENO" 5 fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libffi should be bundled" >&5 +$as_echo_n "checking if libffi should be bundled... " >&6; } + if test "x$enable_libffi_bundling" = "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ENABLE_LIBFFI_BUNDLING=false + elif test "x$enable_libffi_bundling" = "xno"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, forced" >&5 +$as_echo "no, forced" >&6; } + ENABLE_LIBFFI_BUNDLING=false + elif test "x$enable_libffi_bundling" = "xyes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, forced" >&5 +$as_echo "yes, forced" >&6; } + ENABLE_LIBFFI_BUNDLING=true + else + as_fn_error $? "Invalid value for --enable-libffi-bundling" "$LINENO" 5 + fi + + # Find the libffi.so.X to bundle + if test "x${ENABLE_LIBFFI_BUNDLING}" = "xtrue"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libffi lib file location" >&5 +$as_echo_n "checking for libffi lib file location... " >&6; } + 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 + as_fn_error $? "Could not locate libffi.so.? for bundling in ${LIBFFI_LIB_PATH}" "$LINENO" 5 + 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 + as_fn_error $? "Could not locate libffi.so.? for bundling" "$LINENO" 5 + 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 + as_fn_error $? "Could not locate libffi.so.? for bundling" "$LINENO" 5 + 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 + as_fn_error $? "Could not locate libffi.so.? for bundling" "$LINENO" 5 + fi + fi + fi + # Make sure the wildcard is evaluated + LIBFFI_LIB_FILE="$(ls ${LIBFFI_LIB_FILE})" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${LIBFFI_LIB_FILE}" >&5 +$as_echo "${LIBFFI_LIB_FILE}" >&6; } + fi fi + + if [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then # Extract the first word of "llvm-config", so it can be a program name with args. set dummy llvm-config; ac_word=$2 @@ -65521,6 +65519,13 @@ $as_echo "$as_me: WARNING: --with-ccache-dir has no meaning when ccache is not e if test "x$CCACHE" != x; then 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 + as_fn_error $? "On macosx, ccache 3.2 or later is required, found $CCACHE_VERSION" "$LINENO" 5 + 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]$'` diff --git a/common/autoconf/help.m4 b/common/autoconf/help.m4 index e7ccdca3cf3..98e2a9258b5 100644 --- a/common/autoconf/help.m4 +++ b/common/autoconf/help.m4 @@ -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) diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 index 8becdf3669c..acc0dccf8c4 100644 --- a/common/autoconf/jdk-options.m4 +++ b/common/autoconf/jdk-options.m4 @@ -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) ]) ################################################################################ diff --git a/common/autoconf/jdk-version.m4 b/common/autoconf/jdk-version.m4 index 4846c12647c..949f4276fd4 100644 --- a/common/autoconf/jdk-version.m4 +++ b/common/autoconf/jdk-version.m4 @@ -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=`$DATE '+%Y-%m-%d-%H%M%S'` + # Default is to calculate a string like this 'adhoc..' # 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 diff --git a/common/autoconf/lib-ffi.m4 b/common/autoconf/lib-ffi.m4 index b4b36f12e5b..2a714f3a0b9 100644 --- a/common/autoconf/lib-ffi.m4 +++ b/common/autoconf/lib-ffi.m4 @@ -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) ]) diff --git a/common/autoconf/lib-x11.m4 b/common/autoconf/lib-x11.m4 index 0614299e849..d4b878d8c54 100644 --- a/common/autoconf/lib-x11.m4 +++ b/common/autoconf/lib-x11.m4 @@ -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 diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4 index e7ffe4a2fa5..392a23ad4cd 100644 --- a/common/autoconf/platform.m4 +++ b/common/autoconf/platform.m4 @@ -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" diff --git a/common/autoconf/source-dirs.m4 b/common/autoconf/source-dirs.m4 index 940707e81a0..81137cf95ff 100644 --- a/common/autoconf/source-dirs.m4 +++ b/common/autoconf/source-dirs.m4 @@ -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 diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index e2d7be936f6..fa16d6bc266 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -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@ diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index db3d39e2655..16b0df04b4f 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -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], [ diff --git a/common/autoconf/toolchain_windows.m4 b/common/autoconf/toolchain_windows.m4 index 4a40fa63a91..f2304df0fe9 100644 --- a/common/autoconf/toolchain_windows.m4 +++ b/common/autoconf/toolchain_windows.m4 @@ -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]) diff --git a/common/bin/compare.sh b/common/bin/compare.sh index 21c9051e426..de909e0154c 100644 --- a/common/bin/compare.sh +++ b/common/bin/compare.sh @@ -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 diff --git a/common/bin/compare_exceptions.sh.incl b/common/bin/compare_exceptions.sh.incl index a4c4278299a..5042cdcc104 100644 --- a/common/bin/compare_exceptions.sh.incl +++ b/common/bin/compare_exceptions.sh.incl @@ -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 " diff --git a/common/conf/jib-profiles.js b/common/conf/jib-profiles.js index fa3c5749f8c..8c0f3a7d23b 100644 --- a/common/conf/jib-profiles.js +++ b/common/conf/jib-profiles.js @@ -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", diff --git a/corba/.hgignore b/corba/.hgignore index 5e6b22f24ee..d782b284ae1 100644 --- a/corba/.hgignore +++ b/corba/.hgignore @@ -2,5 +2,4 @@ ^dist/ ^webrev /nbproject/private/ -^.hgtip .DS_Store diff --git a/corba/.hgtags b/corba/.hgtags index c96fdd40202..02f91e90c58 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -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 diff --git a/corba/src/java.corba/share/classes/module-info.java b/corba/src/java.corba/share/classes/module-info.java index 58cff065605..10a26f0bc21 100644 --- a/corba/src/java.corba/share/classes/module-info.java +++ b/corba/src/java.corba/share/classes/module-info.java @@ -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; } diff --git a/hotspot/.hgignore b/hotspot/.hgignore index f7628dd32dc..0c053adb87c 100644 --- a/hotspot/.hgignore +++ b/hotspot/.hgignore @@ -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\.]*/\..* + diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 4ff5566b655..3a531937f19 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -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 diff --git a/hotspot/make/CompileTools.gmk b/hotspot/make/CompileTools.gmk new file mode 100644 index 00000000000..ea6c504e283 --- /dev/null +++ b/hotspot/make/CompileTools.gmk @@ -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 diff --git a/hotspot/make/copy/Copy-java.base.gmk b/hotspot/make/copy/Copy-java.base.gmk index ffb6e30dae5..2185b60396e 100644 --- a/hotspot/make/copy/Copy-java.base.gmk +++ b/hotspot/make/copy/Copy-java.base.gmk @@ -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 + +################################################################################ diff --git a/hotspot/make/gensrc/Gensrc-jdk.vm.compiler.gmk b/hotspot/make/gensrc/Gensrc-jdk.vm.compiler.gmk new file mode 100644 index 00000000000..f12a2e9a5a2 --- /dev/null +++ b/hotspot/make/gensrc/Gensrc-jdk.vm.compiler.gmk @@ -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 diff --git a/hotspot/make/gensrc/GensrcJvmti.gmk b/hotspot/make/gensrc/GensrcJvmti.gmk index b834eae5673..d91c2b6346f 100644 --- a/hotspot/make/gensrc/GensrcJvmti.gmk +++ b/hotspot/make/gensrc/GensrcJvmti.gmk @@ -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. diff --git a/hotspot/make/lib/CompileLibjsig.gmk b/hotspot/make/lib/CompileLibjsig.gmk index d91993d65af..fbc8abb1ca3 100644 --- a/hotspot/make/lib/CompileLibjsig.gmk +++ b/hotspot/make/lib/CompileLibjsig.gmk @@ -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 diff --git a/hotspot/make/lib/JvmFeatures.gmk b/hotspot/make/lib/JvmFeatures.gmk index 0cb2e3c1111..00b3f397e4d 100644 --- a/hotspot/make/lib/JvmFeatures.gmk +++ b/hotspot/make/lib/JvmFeatures.gmk @@ -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 diff --git a/hotspot/make/lib/Lib-jdk.aot.gmk b/hotspot/make/lib/Lib-jdk.aot.gmk new file mode 100644 index 00000000000..d799fa45286 --- /dev/null +++ b/hotspot/make/lib/Lib-jdk.aot.gmk @@ -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 + +############################################################################## diff --git a/hotspot/make/symbols/symbols-unix b/hotspot/make/symbols/symbols-unix index cee0c5f71a8..90326d263dc 100644 --- a/hotspot/make/symbols/symbols-unix +++ b/hotspot/make/symbols/symbols-unix @@ -190,8 +190,6 @@ JVM_AddModuleExportsToAll JVM_AddModuleExportsToAllUnnamed JVM_AddModulePackage JVM_AddReadsModule -JVM_CanReadModule JVM_DefineModule -JVM_IsExportedToModule JVM_SetBootLoaderUnnamedModule JVM_GetModuleByPackageName diff --git a/hotspot/make/test/JtregNative.gmk b/hotspot/make/test/JtregNative.gmk index cca48d09435..7223733367a 100644 --- a/hotspot/make/test/JtregNative.gmk +++ b/hotspot/make/test/JtregNative.gmk @@ -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 diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index 8f58c83136c..24bce03d1a4 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -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) %{ diff --git a/hotspot/src/cpu/aarch64/vm/abstractInterpreter_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/abstractInterpreter_aarch64.cpp index a09f2684af6..adb30aa0d1d 100644 --- a/hotspot/src/cpu/aarch64/vm/abstractInterpreter_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/abstractInterpreter_aarch64.cpp @@ -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; diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp index 8740d2831ea..66686fd0d60 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp @@ -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(); } diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.hpp index f12fa864a2f..95b89dd3fc5 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.hpp @@ -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 diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp index 033741723e8..96793e632b9 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp @@ -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) { diff --git a/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.cpp index 046be55e4e5..47fda46dd23 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.cpp @@ -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); diff --git a/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp index 24389643ca0..490e22507b6 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp @@ -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 diff --git a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp index f6339d7976c..58ba9c0b613 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp @@ -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); diff --git a/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp index 1999b0f95be..3059ad37bc6 100644 --- a/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp @@ -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); diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index 76ffc9d701a..dc90886ab68 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -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, diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp index 207292afa53..3418189f1b4 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp @@ -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, diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp index 383f26118af..90dcd6c1a2c 100644 --- a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp @@ -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: ; } diff --git a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp index 53a294b8601..33cb9496a91 100644 --- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp @@ -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)) { diff --git a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp index d9e17216563..bba0c6d5254 100644 --- a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp @@ -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(); } diff --git a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp index 543156c0951..ab4688e14fd 100644 --- a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp @@ -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 diff --git a/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp index dc2c40d4f6c..377680a47eb 100644 --- a/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp @@ -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<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); } } diff --git a/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp b/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp index 6ff77e028fe..4635ec71f06 100644 --- a/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp @@ -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); diff --git a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp index 953a4d2134f..4173008abac 100644 --- a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp @@ -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, \ diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index 110ed85e12e..2d1f0c7230b 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -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)<=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 (00). 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); } diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp index 7763c86a1dd..11b966a82c9 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -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 diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index 91b5756802b..a8c42b7ac21 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -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); %} diff --git a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp index c367b8efb6d..4299728eacc 100644 --- a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp +++ b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp @@ -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. } diff --git a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.hpp b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.hpp index eed06792467..2414001a2fa 100644 --- a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.hpp +++ b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.hpp @@ -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 diff --git a/hotspot/src/cpu/s390/vm/compiledIC_s390.cpp b/hotspot/src/cpu/s390/vm/compiledIC_s390.cpp index 33e383b30e6..b183404467b 100644 --- a/hotspot/src/cpu/s390/vm/compiledIC_s390.cpp +++ b/hotspot/src/cpu/s390/vm/compiledIC_s390.cpp @@ -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. diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index a0f1982bbd7..97fb2745a26 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -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(); } diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp index 1b13f28f127..c46d0002af3 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp @@ -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 diff --git a/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp b/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp index 46024341022..3be40c8cd3d 100644 --- a/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp @@ -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); diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index 43e1e00e485..8aa4aec76b6 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -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(); } diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp index f9514edef45..680793b1891 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp @@ -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 diff --git a/hotspot/src/cpu/x86/vm/compiledIC_aot_x86_64.cpp b/hotspot/src/cpu/x86/vm/compiledIC_aot_x86_64.cpp new file mode 100644 index 00000000000..6b711506fab --- /dev/null +++ b/hotspot/src/cpu/x86/vm/compiledIC_aot_x86_64.cpp @@ -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 diff --git a/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp b/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp index 6d4c06f19ff..0e8f146bf62 100644 --- a/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp +++ b/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp @@ -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); diff --git a/hotspot/src/cpu/x86/vm/icBuffer_x86.cpp b/hotspot/src/cpu/x86/vm/icBuffer_x86.cpp index dc45fa7f65c..58451eb15d2 100644 --- a/hotspot/src/cpu/x86/vm/icBuffer_x86.cpp +++ b/hotspot/src/cpu/x86/vm/icBuffer_x86.cpp @@ -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; } diff --git a/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp b/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp index 26c6f3392ad..cb8c08f4652 100644 --- a/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp +++ b/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp @@ -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"); diff --git a/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp b/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp index 1bb1c6c8aff..7db3ccb9d3c 100644 --- a/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp +++ b/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp @@ -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() { diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 180a3abed4a..195c6814238 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -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); } diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp index e82c70d9eb2..eb5661bee00 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp @@ -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); diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index dd8e5beba6e..99ae5f5f738 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -2147,6 +2147,9 @@ encode %{ ciEnv::current()->record_failure("CodeCache is full"); return; } +#if INCLUDE_AOT + CompiledStaticCall::emit_to_aot_stub(cbuf, mark); +#endif } %} diff --git a/hotspot/src/cpu/zero/vm/compiledIC_zero.cpp b/hotspot/src/cpu/zero/vm/compiledIC_zero.cpp index 8f912db7bf9..1dbe95222ba 100644 --- a/hotspot/src/cpu/zero/vm/compiledIC_zero.cpp +++ b/hotspot/src/cpu/zero/vm/compiledIC_zero.cpp @@ -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. } diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java new file mode 100644 index 00000000000..7be7a80192e --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java @@ -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. + * + *

+ * 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. + * + *

+ * 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. + * + *

+ * 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 offsetStringTable = new HashMap<>(); + + private final Map metaspaceNames = new HashMap<>(); + + // List of relocation table entries - (symbolName, relocationInfo) + private final Map symbolTable = new HashMap<>(); + private final Map> relocationTable = new HashMap<>(); + private final Map uniqueRelocationTable = new HashMap<>(); + + /** + * Mapping of local VM function names to known global symbols generated in the output binary. + */ + private static final HashMap 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 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 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: + // "Ljava/lang/ThreadGroup;addUnstarted()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 getUniqueRelocationTable() { + return uniqueRelocationTable; + } + + public HeaderContainer getHeaderContainer() { + return headerContainer; + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ByteContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ByteContainer.java new file mode 100644 index 00000000000..12daa9f356f --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ByteContainer.java @@ -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; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java new file mode 100644 index 00000000000..e562d35e2cc --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java @@ -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); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java new file mode 100644 index 00000000000..3d77e79f35f --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java @@ -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); + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java new file mode 100644 index 00000000000..85250d3973e --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java @@ -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); + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java new file mode 100644 index 00000000000..fe72f068d79 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java @@ -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); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java new file mode 100644 index 00000000000..e7d1e3f1c33 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java @@ -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; + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java new file mode 100644 index 00000000000..ba0f9090ee7 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java @@ -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 + "]"; + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/SymbolTable.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/SymbolTable.java new file mode 100644 index 00000000000..d5d690c8e6c --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/SymbolTable.java @@ -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); +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java new file mode 100644 index 00000000000..82bac0c7170 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java @@ -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> relocationTable, Collection 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> 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 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 localSymbols = elfContainer.getLocalSymbols(); + List 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> relocationTable) { + /* + * For each of the symbols with associated relocation records, create an ELF relocation + * entry. + */ + for (Map.Entry> entry : relocationTable.entrySet()) { + List relocs = entry.getValue(); + Symbol symbol = entry.getKey(); + + for (Relocation reloc : relocs) { + createRelocation(symbol, reloc); + } + } + + for (Map.Entry 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__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> entry : elfContainer.getRelocTables().entrySet()) { + createRelocationSection(entry.getKey(), entry.getValue(), symtab); + } + } + + private void createRelocationSection(ELFContainer container, ArrayList 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; + } + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/ELFContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/ELFContainer.java new file mode 100644 index 00000000000..b65b6ae8d25 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/ELFContainer.java @@ -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(); + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/ELFSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/ELFSymbol.java new file mode 100644 index 00000000000..ddad5a018da --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/ELFSymbol.java @@ -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; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFContainer.java new file mode 100644 index 00000000000..64d699f0371 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFContainer.java @@ -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 localSymbolIndex = new ArrayList<>(); + + /** + * Map of global symbol indexes to ELF symbol entries. + */ + private List 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> 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 getLocalSymbols() { + return localSymbolIndex; + } + + /** + * Get the global ELF symbol table. + * + * @return list of global ELF symbol table entries + */ + public List 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> 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; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFRelocation.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFRelocation.java new file mode 100644 index 00000000000..4c4cffd7abe --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFRelocation.java @@ -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; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFTargetInfo.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFTargetInfo.java new file mode 100644 index 00000000000..8248d6fba29 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFTargetInfo.java @@ -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); + } + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNILibELFAPI.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNILibELFAPI.java new file mode 100644 index 00000000000..5dc277b16ed --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNILibELFAPI.java @@ -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 +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/Pointer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/Pointer.java new file mode 100644 index 00000000000..a569584a8ce --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/Pointer.java @@ -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); + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/UnsafeAccess.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/UnsafeAccess.java new file mode 100644 index 00000000000..08e271028b6 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/UnsafeAccess.java @@ -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(); + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/linux/Elf_Cmd.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/linux/Elf_Cmd.java new file mode 100644 index 00000000000..a32d202486c --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/linux/Elf_Cmd.java @@ -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; +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/sunos/Elf_Cmd.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/sunos/Elf_Cmd.java new file mode 100644 index 00000000000..be7423c1cad --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/sunos/Elf_Cmd.java @@ -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 + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java new file mode 100644 index 00000000000..b5d081a51ca --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java @@ -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 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 initGraphBuilderSuite(HotSpotBackend backend) { + PhaseSuite graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); + ListIterator> 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); + } + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java new file mode 100644 index 00000000000..f92ead4ba25 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java @@ -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 { + + 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; + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java new file mode 100644 index 00000000000..cbf26294b0d --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java @@ -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 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 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 klassData = new HashMap<>(); + + /** + * List of all methods to be compiled. + */ + private ArrayList methods = new ArrayList<>(); + + /** + * List of all compiled class methods. + */ + private ArrayList 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 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 getMethods() { + ArrayList 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 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; + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java new file mode 100644 index 00000000000..12a72c42dfa --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java @@ -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 compileClasses(List 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 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); + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java new file mode 100644 index 00000000000..865ef46c89a --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java @@ -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); + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java new file mode 100644 index 00000000000..b7ba5e87e72 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java @@ -0,0 +1,54 @@ +/* + * 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.core.target.Backend; +import org.graalvm.compiler.hotspot.stubs.Stub; + +import jdk.vm.ci.hotspot.HotSpotCompiledCode; + +public class AOTStub implements JavaMethodInfo { + + private final Stub stub; + private final Backend backend; + + public AOTStub(Stub stub, Backend backend) { + this.stub = stub; + this.backend = backend; + } + + public String getSymbolName() { + return stub.toString(); + } + + public String getNameAndSignature() { + return stub.toString(); + } + + public HotSpotCompiledCode compiledCode(CompilationResult result) { + return stub.getCompiledCode(backend); + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java new file mode 100644 index 00000000000..72d9e532696 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java @@ -0,0 +1,42 @@ +/* + * 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 jdk.tools.jaotc.binformat.Relocation.RelocType; + +/** + * Describes a call site relocation. Contains a name of the callee and a relocation type, describing + * which relocation to use at the call site. + */ +abstract class CallSiteRelocationInfo { + + public final String targetSymbol; + public final RelocType type; + + public CallSiteRelocationInfo(String targetSymbol, RelocType type) { + this.targetSymbol = targetSymbol; + this.type = type; + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java new file mode 100644 index 00000000000..68f86ef65e3 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java @@ -0,0 +1,88 @@ +/* + * 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 jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.ByteContainer; +import jdk.tools.jaotc.binformat.CodeContainer; +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; + +/** + * Describes a relocation symbol of a call site. That is, WHERE to do a relocation. + */ +abstract class CallSiteRelocationSymbol { + + public final Symbol symbol; + + public CallSiteRelocationSymbol(Symbol symbol) { + assert symbol != null; + this.symbol = symbol; + } + + protected static Symbol createCodeContainerSymbol(BinaryContainer binaryContainer, String symbolName, int symbolOffset) { + return binaryContainer.getCodeContainer().createSymbol(symbolOffset, Kind.OBJECT, Binding.LOCAL, 0, symbolName); + } + + protected static void addCodeContainerRelocation(BinaryContainer binaryContainer, String symbolName, int symbolOffset, int relocationOffset) { + Symbol symbol = createCodeContainerSymbol(binaryContainer, symbolName, symbolOffset); + addExternalGotToPltRelocation(binaryContainer, symbol, relocationOffset); + } + + protected static void addExtLinkageGotContainerRelocation(BinaryContainer binaryContainer, String symbolName, int symbolOffset, int relocationOffset) { + ByteContainer container = binaryContainer.getExtLinkageGOTContainer(); + Symbol symbol = container.createGotSymbol(symbolOffset, symbolName); + addExternalPltToGotRelocation(binaryContainer, symbol, relocationOffset); + } + + protected static void addMetaspaceGotRelocation(BinaryContainer binaryContainer, String symbolName, int symbolOffset, int relocationOffset) { + ByteContainer container = binaryContainer.getMetaspaceGotContainer(); + Symbol symbol = container.createGotSymbol(symbolOffset, symbolName); + addExternalPltToGotRelocation(binaryContainer, symbol, relocationOffset); + } + + /** + * Add an {@link RelocType#EXTERNAL_GOT_TO_PLT} relocation to the + * {@link BinaryContainer#getExtLinkageGOTContainer()}. + */ + private static void addExternalGotToPltRelocation(BinaryContainer binaryContainer, Symbol symbol, int relocationOffset) { + ByteContainer container = binaryContainer.getExtLinkageGOTContainer(); + Relocation relocation = new Relocation(relocationOffset, RelocType.EXTERNAL_GOT_TO_PLT, 8, container, symbol); + binaryContainer.addRelocation(relocation); + } + + /** + * Add an {@link RelocType#EXTERNAL_PLT_TO_GOT} relocation to the + * {@link BinaryContainer#getCodeContainer()}. + */ + protected static void addExternalPltToGotRelocation(BinaryContainer binaryContainer, Symbol symbol, int relocationOffset) { + CodeContainer container = binaryContainer.getCodeContainer(); + Relocation relocation = new Relocation(relocationOffset, RelocType.EXTERNAL_PLT_TO_GOT, 8, container, symbol); + binaryContainer.addRelocation(relocation); + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java new file mode 100644 index 00000000000..35e54cab229 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java @@ -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; + +import java.util.List; + +import jdk.vm.ci.code.site.Mark; + +public final class CodeOffsets { + private final int entry; + private final int verifiedEntry; + private final int exceptionHandler; + private final int deoptHandler; + + private CodeOffsets(int entry, int verifiedEntry, int exceptionHandler, int deoptHandler) { + this.entry = entry; + this.verifiedEntry = verifiedEntry; + this.exceptionHandler = exceptionHandler; + this.deoptHandler = deoptHandler; + } + + public static CodeOffsets buildFrom(List marks) { + int entry = 0; + int verifiedEntry = 0; + int exceptionHandler = -1; + int deoptHandler = -1; + + for (Mark mark : marks) { + if (mark.id instanceof Integer) { + MarkId markId = MarkId.getEnum((int) mark.id); + switch (markId) { + case UNVERIFIED_ENTRY: + entry = mark.pcOffset; + break; + case VERIFIED_ENTRY: + verifiedEntry = mark.pcOffset; + break; + case OSR_ENTRY: + // Unhandled + break; + case EXCEPTION_HANDLER_ENTRY: + exceptionHandler = mark.pcOffset; + break; + case DEOPT_HANDLER_ENTRY: + deoptHandler = mark.pcOffset; + break; + default: + break; // Ignore others + } + } + } + return new CodeOffsets(entry, verifiedEntry, exceptionHandler, deoptHandler); + } + + public int entry() { + return entry; + } + + public int verifiedEntry() { + return verifiedEntry; + } + + public int exceptionHandler() { + return exceptionHandler; + } + + public int deoptHandler() { + return deoptHandler; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java new file mode 100644 index 00000000000..d1064585786 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java @@ -0,0 +1,142 @@ +/* + * 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 jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.CodeContainer; +import jdk.tools.jaotc.binformat.Symbol; +import jdk.tools.jaotc.CompiledMethodInfo.StubInformation; +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.code.site.InfopointReason; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +class CodeSectionProcessor { + + private final TargetDescription target; + + private final BinaryContainer binaryContainer; + + CodeSectionProcessor(DataBuilder dataBuilder) { + this.target = dataBuilder.getBackend().getTarget(); + this.binaryContainer = dataBuilder.getBinaryContainer(); + } + + /** + * Method that looks at code section of a compiled result {@code compClass} and records function + * entry point symbols along with the text section contents. Note that the text section contents + * are not yet ready to be written in the form of a binary text section since the contents may + * need to be patched with references to other sections. + * + * @param compClass Graal compilation result. + */ + void process(AOTCompiledClass compClass) { + ArrayList compiledMethods = compClass.getCompiledMethods(); + + for (CompiledMethodInfo methodInfo : compiledMethods) { + CompilationResult compResult = methodInfo.getCompilationResult(); + + byte[] targetCode = compResult.getTargetCode(); + int targetCodeSize = compResult.getTargetCodeSize(); + JavaMethodInfo compMethod = methodInfo.getMethodInfo(); + + // Step through all foreign calls, for every call, clear destination. + // Otherwise libelf may not patch them correctly. + for (Infopoint infopoint : compResult.getInfopoints()) { + if (infopoint.reason == InfopointReason.CALL) { + final Call callInfopoint = (Call) infopoint; + if (callInfopoint.target instanceof HotSpotForeignCallLinkage) { + // TODO 4 is x86 size of relative displacement. + // For SPARC need something different. + int destOffset = infopoint.pcOffset + callInfopoint.size - 4; + targetCode[destOffset + 0] = 0; + targetCode[destOffset + 1] = 0; + targetCode[destOffset + 2] = 0; + targetCode[destOffset + 3] = 0; + } + } + } + + String entry = compMethod.getSymbolName(); + assert entry != null : "missing name for compiled method"; + + // Align and pad method entry + CodeContainer codeSection = binaryContainer.getCodeContainer(); + int codeIdOffset = binaryContainer.alignUp(codeSection, binaryContainer.getCodeSegmentSize()); + // Store CodeId into code. It will be use by find_aot() using code.segments + methodInfo.setCodeId(); + binaryContainer.appendIntToCode(methodInfo.getCodeId()); + int textBaseOffset = binaryContainer.alignUp(codeSection, binaryContainer.getCodeEntryAlignment()); + + codeSection.createSymbol(textBaseOffset, Symbol.Kind.JAVA_FUNCTION, Symbol.Binding.LOCAL, targetCodeSize, entry); + + // Set the offset at which the text section of this method would be layed out + methodInfo.setTextSectionOffset(textBaseOffset); + + // Write code bytes of the current method into byte stream + binaryContainer.appendCodeBytes(targetCode, 0, targetCodeSize); + int currentStubOffset = binaryContainer.alignUp(codeSection, 8); + // Set the offset at which stubs of this method would be laid out + methodInfo.setStubsOffset(currentStubOffset - textBaseOffset); + // step through all calls, for every call, add a stub + for (Infopoint infopoint : compResult.getInfopoints()) { + if (infopoint.reason == InfopointReason.CALL) { + final Call callInfopoint = (Call) infopoint; + if (callInfopoint.target instanceof ResolvedJavaMethod) { + ResolvedJavaMethod call = (ResolvedJavaMethod) callInfopoint.target; + StubInformation stub = addCallStub(MiscUtils.isVirtualCall(methodInfo, callInfopoint)); + // Get the targetSymbol. A symbol for this will be created later during plt + // creation + String targetSymbol = MiscUtils.uniqueMethodName(call) + ".at." + infopoint.pcOffset; + methodInfo.addStubCode(targetSymbol, stub); + currentStubOffset += stub.getSize(); + } + } + } + assert currentStubOffset == codeSection.getByteStreamSize() : "wrong offset"; + binaryContainer.addCodeSegments(codeIdOffset, currentStubOffset); + } + } + + private StubInformation addCallStub(boolean isVirtualCall) { + final int startOffset = binaryContainer.getCodeContainer().getByteStreamSize(); + StubInformation stub = new StubInformation(startOffset, isVirtualCall); + ELFMacroAssembler masm = ELFMacroAssembler.getELFMacroAssembler(target); + byte[] code; + if (isVirtualCall) { + code = masm.getPLTVirtualEntryCode(stub); + } else { + code = masm.getPLTStaticEntryCode(stub); + } + binaryContainer.appendCodeBytes(code, 0, code.length); + return stub; + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java new file mode 100644 index 00000000000..b42199d540b --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java @@ -0,0 +1,125 @@ +/* + * 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.HashSet; +import java.util.Iterator; +import java.util.regex.Pattern; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * A class encapsulating any user-specified compilation restrictions. + */ +public class CompilationSpec { + + /** + * Set of method names to restrict compilation to. + */ + private HashSet compileOnlyStrings = new HashSet<>(); + private HashSet compileOnlyPatterns = new HashSet<>(); + + /** + * Set of method names that should be excluded from compilation. + */ + private HashSet excludeStrings = new HashSet<>(); + private HashSet excludePatterns = new HashSet<>(); + + /** + * Add a {@code compileOnly} directive to the compile-only list. + * + * @param pattern regex or non-regex pattern string + */ + public void addCompileOnlyPattern(String pattern) { + if (pattern.contains("*")) { + compileOnlyPatterns.add(Pattern.compile(pattern)); + } else { + compileOnlyStrings.add(pattern); + } + } + + /** + * Add an {@code exclude} directive to the exclude list. + * + * @param pattern regex or non-regex pattern string + */ + public void addExcludePattern(String pattern) { + if (pattern.contains("*")) { + excludePatterns.add(Pattern.compile(pattern)); + } else { + excludeStrings.add(pattern); + } + } + + /** + * Check if a given method is part of a restrictive compilation. + * + * @param method method to be checked + * @return true or false + */ + public boolean shouldCompileMethod(ResolvedJavaMethod method) { + if (compileWithRestrictions()) { + // If there are user-specified compileOnly patterns, default action + // is not to compile the method. + boolean compileMethod = compileOnlyStrings.isEmpty() && compileOnlyPatterns.isEmpty(); + + // Check if the method matches with any of the specified compileOnly patterns. + String methodName = MiscUtils.uniqueMethodName(method); + + // compileOnly + if (!compileMethod) { + compileMethod = compileOnlyStrings.contains(methodName); + } + if (!compileMethod) { + Iterator it = compileOnlyPatterns.iterator(); + while (!compileMethod && it.hasNext()) { + Pattern pattern = it.next(); + compileMethod = pattern.matcher(methodName).matches(); + } + } + + // exclude + if (compileMethod) { + compileMethod = !excludeStrings.contains(methodName); + } + if (compileMethod) { + Iterator it = excludePatterns.iterator(); + while (compileMethod && it.hasNext()) { + Pattern pattern = it.next(); + compileMethod = !(pattern.matcher(methodName).matches()); + } + } + return compileMethod; + } + return true; + } + + /** + * Return true if compilation restrictions are specified. + */ + private boolean compileWithRestrictions() { + return !(compileOnlyStrings.isEmpty() && compileOnlyPatterns.isEmpty() && excludeStrings.isEmpty() && excludePatterns.isEmpty()); + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java new file mode 100644 index 00000000000..2ccafbf7f2f --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java @@ -0,0 +1,441 @@ +/* + * 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.atomic.AtomicInteger; +import java.util.HashMap; +import java.util.Map; + +import jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.ReadOnlyDataContainer; +import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData; +import org.graalvm.compiler.code.CompilationResult; + +import jdk.vm.ci.code.site.Mark; +import jdk.vm.ci.code.site.Site; +import jdk.vm.ci.hotspot.HotSpotCompiledCode; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; + +public class CompiledMethodInfo { + + public static class StubInformation { + int stubOffset; // the offset inside the code (text + stubOffset) + int stubSize; // the stub size + int dispatchJumpOffset; // offset after main dispatch jump instruction + int resolveJumpOffset; // offset after jump instruction to runtime call resolution + // function. + int resolveJumpStart; // offset of jump instruction to VM runtime call resolution + // function. + int c2iJumpOffset; // offset after jump instruction to c2i adapter for static calls. + int movOffset; // offset after move instruction which loads from got cell: + // - Method* for static call + // - Klass* for virtual call + + boolean isVirtual; // virtual call stub + + // maybe add type of stub as well, right now we only have static stubs + + public StubInformation(int stubOffset, boolean isVirtual) { + this.stubOffset = stubOffset; + this.isVirtual = isVirtual; + this.stubSize = -1; + this.movOffset = -1; + this.c2iJumpOffset = -1; + this.resolveJumpOffset = -1; + this.resolveJumpStart = -1; + this.dispatchJumpOffset = -1; + } + + public int getOffset() { + return stubOffset; + } + + public boolean isVirtual() { + return isVirtual; + } + + public void setSize(int stubSize) { + this.stubSize = stubSize; + } + + public int getSize() { + return stubSize; + } + + public void setMovOffset(int movOffset) { + this.movOffset = movOffset + stubOffset; + } + + public int getMovOffset() { + return movOffset; + } + + public void setC2IJumpOffset(int c2iJumpOffset) { + this.c2iJumpOffset = c2iJumpOffset + stubOffset; + } + + public int getC2IJumpOffset() { + return c2iJumpOffset; + } + + public void setResolveJumpOffset(int resolveJumpOffset) { + this.resolveJumpOffset = resolveJumpOffset + stubOffset; + } + + public int getResolveJumpOffset() { + return resolveJumpOffset; + } + + public void setResolveJumpStart(int resolveJumpStart) { + this.resolveJumpStart = resolveJumpStart + stubOffset; + } + + public int getResolveJumpStart() { + return resolveJumpStart; + } + + public void setDispatchJumpOffset(int dispatchJumpOffset) { + this.dispatchJumpOffset = dispatchJumpOffset + stubOffset; + } + + public int getDispatchJumpOffset() { + return dispatchJumpOffset; + } + + public void verify() { + assert stubOffset > 0 : "incorrect stubOffset: " + stubOffset; + assert stubSize > 0 : "incorrect stubSize: " + stubSize; + assert movOffset > 0 : "incorrect movOffset: " + movOffset; + assert dispatchJumpOffset > 0 : "incorrect dispatchJumpOffset: " + dispatchJumpOffset; + assert resolveJumpStart > 0 : "incorrect resolveJumpStart: " + resolveJumpStart; + assert resolveJumpOffset > 0 : "incorrect resolveJumpOffset: " + resolveJumpOffset; + if (!isVirtual) { + assert c2iJumpOffset > 0 : "incorrect c2iJumpOffset: " + c2iJumpOffset; + } + } + } + + private static final int UNINITIALIZED_OFFSET = -1; + + private static class AOTMethodOffsets { + /** + * Offset in metaspace names section. + */ + private int nameOffset; + + /** + * Offset in the text section at which compiled code starts. + */ + private int textSectionOffset; + + /** + * Offset in the metadata section. + */ + private int metadataOffset; + + /** + * Offset to the metadata in the GOT table. + */ + private int metadataGotOffset; + + /** + * Size of the metadata. + */ + private int metadataGotSize; + + /** + * The sequential number corresponding to the order of methods code in code buffer. + */ + private int codeId; + + public AOTMethodOffsets() { + this.nameOffset = UNINITIALIZED_OFFSET; + this.textSectionOffset = UNINITIALIZED_OFFSET; + this.metadataOffset = UNINITIALIZED_OFFSET; + this.metadataGotOffset = UNINITIALIZED_OFFSET; + this.metadataGotSize = -1; + this.codeId = -1; + } + + protected void addMethodOffsets(ReadOnlyDataContainer container, String name) { + verify(name); + // @formatter:off + /* + * The offsets layout should match AOTMethodOffsets structure in AOT JVM runtime + */ + // Add the offset to the name in the .metaspace.names section + container.appendInt(nameOffset). + // Add the offset to the code in the .text section + appendInt(textSectionOffset). + // Add the offset to the metadata in the .method.metadata section + appendInt(metadataOffset). + // Add the offset to the metadata in the .metadata.got section + appendInt(metadataGotOffset). + // Add the size of the metadata + appendInt(metadataGotSize). + // Add code ID. + appendInt(codeId); + // @formatter:on + } + + private void verify(String name) { + assert nameOffset >= 0 : "incorrect nameOffset: " + nameOffset + " for method: " + name; + assert textSectionOffset > 0 : "incorrect textSectionOffset: " + textSectionOffset + " for method: " + name; + assert metadataOffset >= 0 : "incorrect metadataOffset: " + metadataOffset + " for method: " + name; + assert metadataGotOffset >= 0 : "incorrect metadataGotOffset: " + metadataGotOffset + " for method: " + name; + assert metadataGotSize >= 0 : "incorrect metadataGotSize: " + metadataGotSize + " for method: " + name; + assert codeId >= 0 : "incorrect codeId: " + codeId + " for method: " + name; + } + + protected void setNameOffset(int offset) { + nameOffset = offset; + } + + protected void setTextSectionOffset(int textSectionOffset) { + this.textSectionOffset = textSectionOffset; + } + + protected int getTextSectionOffset() { + return textSectionOffset; + } + + protected void setCodeId(int codeId) { + this.codeId = codeId; + } + + protected int getCodeId() { + return codeId; + } + + protected void setMetadataOffset(int offset) { + metadataOffset = offset; + } + + protected void setMetadataGotOffset(int metadataGotOffset) { + this.metadataGotOffset = metadataGotOffset; + } + + protected void setMetadataGotSize(int length) { + this.metadataGotSize = length; + } + } + + /** + * Method name + */ + private String name; + + /** + * Result of graal compilation. + */ + private CompilationResult compilationResult; + + /** + * HotSpotResolvedJavaMethod or Stub corresponding to the compilation result. + */ + private JavaMethodInfo methodInfo; + + /** + * Compiled code from installation. + */ + private HotSpotCompiledCode code; + + /** + * Offset to stubs. + */ + private int stubsOffset; + + /** + * The total size in bytes of the stub section. + */ + private int totalStubSize; + + /** + * Method's offsets. + */ + private AOTMethodOffsets methodOffsets; + + /** + * List of stubs (PLT trampoline). + */ + private Map stubs = new HashMap<>(); + + /** + * List of referenced classes. + */ + private Map dependentKlasses = new HashMap<>(); + + /** + * Methods count used to generate unique global method id. + */ + private static final AtomicInteger methodsCount = new AtomicInteger(); + + public CompiledMethodInfo(CompilationResult compilationResult, JavaMethodInfo methodInfo) { + this.name = methodInfo.getNameAndSignature(); + this.compilationResult = compilationResult; + this.methodInfo = methodInfo; + this.stubsOffset = UNINITIALIZED_OFFSET; + this.methodOffsets = new AOTMethodOffsets(); + } + + public String name() { + return name; + } + + public void addMethodOffsets(BinaryContainer binaryContainer, ReadOnlyDataContainer container) { + this.methodOffsets.setNameOffset(binaryContainer.addMetaspaceName(name)); + this.methodOffsets.addMethodOffsets(container, name); + for (AOTKlassData data : dependentKlasses.values()) { + data.addDependentMethod(this); + } + } + + public CompilationResult getCompilationResult() { + return compilationResult; + } + + public JavaMethodInfo getMethodInfo() { + return methodInfo; + } + + public void setTextSectionOffset(int textSectionOffset) { + methodOffsets.setTextSectionOffset(textSectionOffset); + } + + public int getTextSectionOffset() { + return methodOffsets.getTextSectionOffset(); + } + + public void setCodeId() { + methodOffsets.setCodeId(CompiledMethodInfo.getNextCodeId()); + } + + public int getCodeId() { + return this.methodOffsets.getCodeId(); + } + + public static int getMethodsCount() { + return methodsCount.get(); + } + + public static int getNextCodeId() { + return methodsCount.getAndIncrement(); + } + + public int getCodeSize() { + return stubsOffset + getStubCodeSize(); + } + + public int getStubCodeSize() { + return totalStubSize; + } + + public void setMetadataOffset(int offset) { + this.methodOffsets.setMetadataOffset(offset); + } + + /** + * Offset into the code of this method where the stub section starts. + */ + public void setStubsOffset(int offset) { + stubsOffset = offset; + } + + public int getStubsOffset() { + return stubsOffset; + } + + public void setMetadataGotOffset(int metadataGotOffset) { + this.methodOffsets.setMetadataGotOffset(metadataGotOffset); + } + + public void setMetadataGotSize(int length) { + this.methodOffsets.setMetadataGotSize(length); + } + + public void addStubCode(String call, StubInformation stub) { + stubs.put(call, stub); + totalStubSize += stub.getSize(); + } + + public StubInformation getStubFor(String call) { + StubInformation stub = stubs.get(call); + assert stub != null : "missing stub for call " + call; + stub.verify(); + return stub; + } + + public void addDependentKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { + AOTKlassData klassData = AOTCompiledClass.addFingerprintKlassData(binaryContainer, type); + String klassName = type.getName(); + + if (dependentKlasses.containsKey(klassName)) { + assert dependentKlasses.get(klassName) == klassData : "duplicated data for klass: " + klassName; + } else { + dependentKlasses.put(klassName, klassData); + } + } + + public AOTKlassData getDependentKlassData(String klassName) { + return dependentKlasses.get(klassName); + } + + public boolean hasMark(Site call, MarkId id) { + for (Mark m : compilationResult.getMarks()) { + // TODO: X64-specific code. + // Call instructions are aligned to 8 + // bytes - 1 on x86 to patch address atomically, + int adjOffset = (m.pcOffset & (-8)) + 7; + // Mark points before aligning nops. + if ((call.pcOffset == adjOffset) && MarkId.getEnum((int) m.id) == id) { + return true; + } + } + return false; + } + + public String asTag() { + return "[" + methodInfo.getSymbolName() + "]"; + } + + public HotSpotCompiledCode compiledCode() { + if (code == null) { + code = methodInfo.compiledCode(compilationResult); + } + return code; + } + + // Free memory + public void clear() { + this.dependentKlasses = null; + this.name = null; + } + + public void clearCompileData() { + this.code = null; + this.stubs = null; + this.compilationResult = null; + this.methodInfo = null; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java new file mode 100644 index 00000000000..350ee46921a --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java @@ -0,0 +1,237 @@ +/* + * 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.List; +import java.util.Map.Entry; + +import jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.ByteContainer; +import jdk.tools.jaotc.binformat.HeaderContainer; +import jdk.tools.jaotc.utils.Timer; +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.hotspot.HotSpotHostBackend; +import org.graalvm.compiler.hotspot.stubs.Stub; + +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotVMConfigStore; +import jdk.vm.ci.hotspot.VMField; + +class DataBuilder { + + private final Main main; + + private final HotSpotHostBackend backend; + + private final List classes; + + /** + * Target-independent container in which text symbols and code bytes are created. + */ + private final BinaryContainer binaryContainer; + + private final HashMap vmAddresses = new HashMap<>(); + + public DataBuilder(Main main, HotSpotHostBackend backend, List classes, BinaryContainer binaryContainer) { + this.main = main; + this.backend = backend; + this.classes = classes; + this.binaryContainer = binaryContainer; + fillVMAddresses(HotSpotJVMCIRuntime.runtime().getConfigStore()); + } + + /** + * Returns a value-name map of all {@link VMField} fields. + */ + private void fillVMAddresses(HotSpotVMConfigStore config) { + for (VMField vmField : config.getFields().values()) { + if (vmField.value != null) { + final long address = vmField.value; + String value = vmField.name; + /* + * Some fields don't contain addresses but integer values. At least don't add zero + * entries to avoid matching null addresses. + */ + if (address != 0) { + vmAddresses.put(address, value); + } + } + } + for (Entry vmAddress : config.getAddresses().entrySet()) { + final long address = vmAddress.getValue(); + String value = vmAddress.getKey(); + String old = vmAddresses.put(address, value); + if (old != null) { + throw new InternalError("already in map: address: " + address + ", current: " + value + ", old: " + old); + } + } + } + + /** + * Get the C/C++ function name associated with the foreign call target {@code address}. + * + * @param address native address + * @return C/C++ functio name associated with the native address + */ + public String getVMFunctionNameForAddress(long address) { + return vmAddresses.get(address); + } + + /** + * Returns the host backend used for this compilation. + * + * @return host backend + */ + public HotSpotHostBackend getBackend() { + return backend; + } + + /** + * Returns the binary container for this compilation. + * + * @return binary container + */ + public BinaryContainer getBinaryContainer() { + return binaryContainer; + } + + /** + * Prepare data with all compiled classes and stubs. + * + * @throws Exception + */ + @SuppressWarnings("try") + public void prepareData() throws Exception { + try (Timer t = new Timer(main, "Parsing compiled code")) { + /* + * Copy compiled code into code section container and calls stubs (PLT trampoline). + */ + CodeSectionProcessor codeSectionProcessor = new CodeSectionProcessor(this); + for (AOTCompiledClass c : classes) { + // For each class we need 2 GOT slots: + // first - for initialized klass + // second - only for loaded klass + c.addAOTKlassData(binaryContainer); + codeSectionProcessor.process(c); + } + } + + AOTCompiledClass stubCompiledCode = retrieveStubCode(); + + // Free memory! + try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) { + main.printMemoryUsage(); + System.gc(); + } + + MetadataBuilder metadataBuilder = null; + try (Timer t = new Timer(main, "Processing metadata")) { + /* + * Generate metadata for compiled code and copy it into metadata section. Create + * relocation information for all references (call, constants, etc) in compiled code. + */ + metadataBuilder = new MetadataBuilder(this); + metadataBuilder.processMetadata(classes, stubCompiledCode); + } + + // Free memory! + try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) { + main.printMemoryUsage(); + System.gc(); + } + + try (Timer t = new Timer(main, "Preparing stubs binary")) { + prepareStubsBinary(stubCompiledCode); + } + try (Timer t = new Timer(main, "Preparing compiled binary")) { + // Should be called after Stubs because they can set dependent klasses. + prepareCompiledBinary(metadataBuilder); + } + } + + /** + * Get all stubs from Graal and add them to the code section. + */ + @SuppressWarnings("try") + private AOTCompiledClass retrieveStubCode() { + ArrayList stubs = new ArrayList<>(); + for (Stub stub : Stub.getStubs()) { + try (Scope scope = Debug.scope("CompileStubs")) { + CompilationResult result = stub.getCompilationResult(backend); + CompiledMethodInfo cm = new CompiledMethodInfo(result, new AOTStub(stub, backend)); + stubs.add(cm); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + AOTCompiledClass stubCompiledCode = new AOTCompiledClass(stubs); + CodeSectionProcessor codeSectionProcessor = new CodeSectionProcessor(this); + codeSectionProcessor.process(stubCompiledCode); + return stubCompiledCode; + } + + /** + * Prepare metaspace.offsets section. + */ + private void prepareCompiledBinary(MetadataBuilder metadataBuilder) { + for (AOTCompiledClass c : classes) { + // Create records for compiled AOT methods. + c.putMethodsData(binaryContainer); + } + // Create records for compiled AOT classes. + AOTCompiledClass.putAOTKlassData(binaryContainer); + + // Fill in AOTHeader + HeaderContainer header = binaryContainer.getHeaderContainer(); + header.setClassesCount(AOTCompiledClass.getClassesCount()); + header.setMethodsCount(CompiledMethodInfo.getMethodsCount()); + // Record size of got sections + ByteContainer bc = binaryContainer.getMetaspaceGotContainer(); + header.setMetaspaceGotSize((bc.getByteStreamSize() / 8)); + bc = binaryContainer.getMetadataGotContainer(); + header.setMetadataGotSize((bc.getByteStreamSize() / 8)); + bc = binaryContainer.getOopGotContainer(); + header.setOopGotSize((bc.getByteStreamSize() / 8)); + } + + /** + * Prepare stubs.offsets section. + */ + private void prepareStubsBinary(AOTCompiledClass compiledClass) { + // For each of the compiled stubs, create records holding information about + // them. + ArrayList compiledStubs = compiledClass.getCompiledMethods(); + int cntStubs = compiledStubs.size(); + binaryContainer.addMethodsCount(cntStubs, binaryContainer.getStubsOffsetsContainer()); + for (CompiledMethodInfo methodInfo : compiledStubs) { + // Note, stubs have different offsets container. + methodInfo.addMethodOffsets(binaryContainer, binaryContainer.getStubsOffsetsContainer()); + } + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java new file mode 100644 index 00000000000..baf1c7b33b2 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java @@ -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; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import jdk.tools.jaotc.binformat.BinaryContainer; +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.AOTCompiledClass.AOTKlassData; +import org.graalvm.compiler.code.DataSection; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.code.site.ConstantReference; +import jdk.vm.ci.code.site.DataPatch; +import jdk.vm.ci.code.site.DataSectionReference; +import jdk.vm.ci.code.site.Reference; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.hotspot.HotSpotSentinelConstant; +import jdk.vm.ci.meta.VMConstant; + +class DataPatchProcessor { + + private final TargetDescription target; + + private final BinaryContainer binaryContainer; + + DataPatchProcessor(DataBuilder dataBuilder) { + this.target = dataBuilder.getBackend().getTarget(); + this.binaryContainer = dataBuilder.getBinaryContainer(); + } + + /** + * Process a {@link DataPatch} generated by the compiler and create all needed binary section + * constructs. + */ + void process(CompiledMethodInfo methodInfo, DataPatch dataPatch) { + Reference reference = dataPatch.reference; + if (reference instanceof ConstantReference) { + processConstantReference(dataPatch, methodInfo); + } else if (reference instanceof DataSectionReference) { + processDataSectionReference(dataPatch, methodInfo); + } else { + throw new InternalError("Unknown data patch reference: " + reference); + } + } + + private void processConstantReference(DataPatch dataPatch, CompiledMethodInfo methodInfo) { + HotSpotConstantLoadAction action = (HotSpotConstantLoadAction) dataPatch.note; + ConstantReference constantReference = (ConstantReference) dataPatch.reference; + assert action != null : "action should be set"; + + VMConstant constant = constantReference.getConstant(); + String targetSymbol = null; + String gotName = null; + if (constant instanceof HotSpotMetaspaceConstant) { + HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant; + if (metaspaceConstant.asResolvedJavaType() != null) { + HotSpotResolvedObjectType type = metaspaceConstant.asResolvedJavaType(); + targetSymbol = type.getName(); + gotName = ((action == HotSpotConstantLoadAction.INITIALIZE) ? "got.init." : "got.") + targetSymbol; + methodInfo.addDependentKlassData(binaryContainer, type); + } else if (metaspaceConstant.asResolvedJavaMethod() != null && action == HotSpotConstantLoadAction.LOAD_COUNTERS) { + targetSymbol = "counters." + MiscUtils.uniqueMethodName(metaspaceConstant.asResolvedJavaMethod()); + gotName = "got." + targetSymbol; + binaryContainer.addMetaspaceSymbol(targetSymbol); + } + } else if (constant instanceof HotSpotObjectConstant) { + // String constant. + HotSpotObjectConstant oopConstant = (HotSpotObjectConstant) constant; + targetSymbol = "ldc." + oopConstant.toValueString(); + Integer offset = binaryContainer.addOopSymbol(targetSymbol); + gotName = "got.ldc." + offset; + } else if (constant instanceof HotSpotSentinelConstant) { + targetSymbol = "state.M" + methodInfo.getCodeId(); + gotName = "got." + targetSymbol; + } + + assert gotName != null : "Unknown constant type: " + constant; + + InstructionDecoder decoder = InstructionDecoder.getInstructionDecoder(target); + decoder.decodePosition(methodInfo.getCompilationResult().getTargetCode(), dataPatch.pcOffset); + int instructionEndOffset = decoder.currentEndOfInstruction(); + + int textBaseOffset = methodInfo.getTextSectionOffset(); + int relocOffset = textBaseOffset + instructionEndOffset; + + Symbol relocationSymbol = binaryContainer.getSymbol(gotName); + assert relocationSymbol != null : "symbol for " + gotName + " missing"; + Relocation reloc = new Relocation(relocOffset, RelocType.METASPACE_GOT_REFERENCE, 0, binaryContainer.getCodeContainer(), relocationSymbol); + binaryContainer.addRelocation(reloc); + } + + private void processDataSectionReference(DataPatch dataPatch, CompiledMethodInfo methodInfo) { + DataSectionReference dataReference = (DataSectionReference) dataPatch.reference; + + InstructionDecoder decoder = InstructionDecoder.getInstructionDecoder(target); + decoder.decodePosition(methodInfo.getCompilationResult().getTargetCode(), dataPatch.pcOffset); + int instructionEndOffset = decoder.currentEndOfInstruction(); + + int textBaseOffset = methodInfo.getTextSectionOffset(); + int relocOffset = textBaseOffset + instructionEndOffset; + int dataOffset = dataReference.getOffset(); + + DataSection dataSection = methodInfo.getCompilationResult().getDataSection(); + DataSection.Data data = dataSection.findData(dataReference); + int size = data.getSize(); + int alignment = data.getAlignment(); + byte[] value = new byte[size]; + ByteBuffer buffer = ByteBuffer.wrap(value).order(ByteOrder.nativeOrder()); + DataSection.emit(buffer, data, p -> { + }); + String targetSymbol = "data.M" + methodInfo.getCodeId() + "." + dataOffset; + Symbol relocationSymbol = binaryContainer.getSymbol(targetSymbol); + if (relocationSymbol == null) { + int symSize = Math.max(8, size); + int symAlig = Math.max(8, alignment); + int offsetInConstantDataSection = binaryContainer.addConstantData(value, symAlig); + relocationSymbol = binaryContainer.getConstantDataContainer().createSymbol(offsetInConstantDataSection, Kind.OBJECT, Binding.LOCAL, symSize, targetSymbol); + } + Relocation reloc = new Relocation(relocOffset, RelocType.METASPACE_GOT_REFERENCE, 0, binaryContainer.getCodeContainer(), relocationSymbol); + binaryContainer.addRelocation(reloc); + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java new file mode 100644 index 00000000000..18ff7af5736 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java @@ -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 jdk.tools.jaotc.CompiledMethodInfo.StubInformation; +import jdk.tools.jaotc.amd64.AMD64ELFMacroAssembler; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.TargetDescription; + +public interface ELFMacroAssembler { + + public static ELFMacroAssembler getELFMacroAssembler(TargetDescription target) { + Architecture architecture = target.arch; + if (architecture instanceof AMD64) { + return new AMD64ELFMacroAssembler(target); + } else { + throw new InternalError("Unsupported architecture " + architecture); + } + } + + public int currentEndOfInstruction(); + + public byte[] getPLTJumpCode(); + + public byte[] getPLTStaticEntryCode(StubInformation stub); + + public byte[] getPLTVirtualEntryCode(StubInformation stub); + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java new file mode 100644 index 00000000000..50c5e4f6cea --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java @@ -0,0 +1,74 @@ +/* + * 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 jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.Relocation.RelocType; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; + +import jdk.vm.ci.code.site.Call; + +/** + * This is a foreign call site. This means either a call to the VM or a call to a Graal stub. If + * it's a call directly to the VM, mangle the name. The call should go through regular .plt used by + * the system loader, at least for now. If it's a call to a Graal stub, it should always be a direct + * call, since the Graal stubs are contained within the .so file. + */ +final class ForeignCallSiteRelocationInfo extends CallSiteRelocationInfo { + + ForeignCallSiteRelocationInfo(Call call, HotSpotForeignCallLinkage callTarget, DataBuilder dataBuilder) { + super(getTargetSymbol(call, callTarget, dataBuilder), getRelocType(callTarget)); + } + + private static String getTargetSymbol(Call call, HotSpotForeignCallLinkage callTarget, DataBuilder dataBuilder) { + // If it specifies a foreign call linkage, find the symbol corresponding to the address in + // HotSpotVMConfig's fields. + final long foreignCallTargetAddress = callTarget.getAddress(); + + // Get the C/C++ function name associated with the foreign call target address. + String functionName = dataBuilder.getVMFunctionNameForAddress(foreignCallTargetAddress); + if (functionName != null) { + // Use the known global AOT symbol associated with function name, if one exists + BinaryContainer binaryContainer = dataBuilder.getBinaryContainer(); + String aotSymbol = binaryContainer.getAOTSymbolForVMFunctionName(functionName); + if (aotSymbol == null) { + throw new InternalError("no global symbol found for: " + functionName); + } + return aotSymbol; + } + + // Is it a Graal stub we are calling? + if (callTarget.isCompiledStub()) { + assert call.direct : "Should always be a direct call to stubs"; + return callTarget.getSymbol(); + } + + throw new InternalError("no symbol found for: " + callTarget); + } + + private static RelocType getRelocType(HotSpotForeignCallLinkage callTarget) { + return callTarget.isCompiledStub() ? RelocType.STUB_CALL_DIRECT : RelocType.FOREIGN_CALL_INDIRECT_GOT; + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java new file mode 100644 index 00000000000..e1fdbe1aee6 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java @@ -0,0 +1,39 @@ +/* + * 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 jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.Symbol.Binding; +import jdk.tools.jaotc.binformat.Symbol.Kind; + +/** + * Native function call, symbol is to a VM method. + */ +final class ForeignCallSiteRelocationSymbol extends CallSiteRelocationSymbol { + + public ForeignCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) { + super(binaryContainer.createSymbol(0, Kind.NATIVE_FUNCTION, Binding.GLOBAL, 0, callSiteRelocation.targetSymbol)); + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java new file mode 100644 index 00000000000..6b55f28cd9b --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java @@ -0,0 +1,70 @@ +/* + * 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 jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.Symbol; + +import jdk.vm.ci.code.site.Call; + +final class ForeignGotCallSiteRelocationSymbol extends CallSiteRelocationSymbol { + + public ForeignGotCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, DataBuilder dataBuilder) { + super(createPltSymbol(dataBuilder, mi, call, callSiteRelocation)); + } + + private static Symbol createPltSymbol(DataBuilder dataBuilder, CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation) { + BinaryContainer binaryContainer = dataBuilder.getBinaryContainer(); + String vmSymbolName = callSiteRelocation.targetSymbol; + + // Add relocation to GOT cell for call resolution jump. + String pltSymbolName = "plt." + vmSymbolName; + Symbol pltSymbol = binaryContainer.getSymbol(pltSymbolName); + + if (pltSymbol == null) { + String gotSymbolName = "got." + vmSymbolName; + Symbol gotSymbol = binaryContainer.getGotSymbol(gotSymbolName); + assert gotSymbol != null : "undefined VM got symbol '" + gotSymbolName + "' for call at " + call.pcOffset + " in " + mi.getMethodInfo().getSymbolName(); + + // Generate PLT jump (do it only once). + final int pltStartOffset = binaryContainer.getCodeContainer().getByteStreamSize(); + final int pltEndOffset = pltStartOffset + addPltJump(dataBuilder); + + // Link GOT cell to PLT jump. + pltSymbol = createCodeContainerSymbol(binaryContainer, pltSymbolName, pltStartOffset); + addExternalPltToGotRelocation(binaryContainer, gotSymbol, pltEndOffset); + } + + return pltSymbol; + } + + private static int addPltJump(DataBuilder dataBuilder) { + ELFMacroAssembler masm = ELFMacroAssembler.getELFMacroAssembler(dataBuilder.getBackend().getTarget()); + byte[] code = masm.getPLTJumpCode(); // It includes alignment nops. + int size = masm.currentEndOfInstruction(); + dataBuilder.getBinaryContainer().appendCodeBytes(code, 0, code.length); + return size; + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java new file mode 100644 index 00000000000..d9cb0b27aef --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java @@ -0,0 +1,139 @@ +/* + * 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.lang.annotation.Annotation; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions; +import org.graalvm.compiler.hotspot.word.MetaspacePointer; +import org.graalvm.compiler.replacements.Snippets; +import org.graalvm.compiler.word.WordBase; + +public class GraalFilters { + private List specialClasses; + private List specialArgumentAndReturnTypes; + + private static Set> skipAnnotations = new HashSet<>(); + + static { + skipAnnotations.add(NodeIntrinsic.class); + skipAnnotations.add(Snippet.class); + skipAnnotations.add(MethodSubstitution.class); + } + + public boolean shouldCompileMethod(ResolvedJavaMethod method) { + // NodeIntrinsics cannot be compiled. + if (hasExcludedAnnotation(method)) { + return false; + } + + ResolvedJavaType declaringClass = method.getDeclaringClass(); + // Check for special magical types in the signature, like Word or MetaspacePointer. Those + // are definitely snippets. + List signatureTypes = Arrays.asList(method.toParameterTypes()).stream().map(p -> p.resolve(declaringClass)).collect(Collectors.toList()); + signatureTypes.add(method.getSignature().getReturnType(null).resolve(declaringClass)); + if (signatureTypes.stream().flatMap(t -> specialArgumentAndReturnTypes.stream().filter(s -> s.isAssignableFrom(t))).findAny().isPresent()) { + return false; + } + return true; + } + + private static boolean hasExcludedAnnotation(ResolvedJavaMethod method) { + for (Annotation annotation : method.getAnnotations()) { + if (skipAnnotations.contains(annotation.annotationType())) { + return true; + } + } + return false; + } + + public boolean shouldCompileAnyMethodInClass(ResolvedJavaType klass) { + if (specialClasses.stream().filter(s -> s.isAssignableFrom(klass)).findAny().isPresent()) { + return false; + } + return true; + } + + // Don't compile methods in classes and their subtypes that are in the list. + private static List getSpecialClasses(MetaAccessProvider meta) { + // @formatter:off + return Arrays.asList(meta.lookupJavaType(Snippets.class), + meta.lookupJavaType(HotSpotClassSubstitutions.class), + meta.lookupJavaType(GraalDirectives.class), + meta.lookupJavaType(ClassSubstitution.class)); + // @formatter:on + } + + // Don't compile methods that have have the listed class or their subtypes in their signature. + private static List getSpecialArgumentAndReturnTypes(MetaAccessProvider meta) { + // @formatter:off + return Arrays.asList(meta.lookupJavaType(WordBase.class), + meta.lookupJavaType(MetaspacePointer.class)); + // @formatter:on + } + + GraalFilters(MetaAccessProvider metaAccess) { + specialClasses = getSpecialClasses(metaAccess); + specialArgumentAndReturnTypes = getSpecialArgumentAndReturnTypes(metaAccess); + } + + public boolean shouldIgnoreException(Throwable e) { + if (e instanceof GraalError) { + String m = e.getMessage(); + if (m.contains("ArrayKlass::_component_mirror")) { + // When compiling Graal, ignore errors in JDK8 snippets. + return true; + } + } + + if (e instanceof org.graalvm.compiler.java.BytecodeParser.BytecodeParserError) { + Throwable cause = e.getCause(); + if (cause instanceof GraalError) { + String m = cause.getMessage(); + // When compiling Graal suppress attempts to compile snippet fragments that bottom + // out with node intrinsics. These are unfortunately not explicitly marked, so we + // have to try to compile them and bail out if we think it's a snippet. + if (m.contains("@NodeIntrinsic method") && m.contains("must only be called from within a replacement")) { + return true; + } + } + } + return false; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java new file mode 100644 index 00000000000..9f68df2b683 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java @@ -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; + +import jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.Relocation; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; + +import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.code.DebugInfo; +import jdk.vm.ci.code.VirtualObject; +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.InvokeTarget; + +class InfopointProcessor { + + private final DataBuilder dataBuilder; + + private final BinaryContainer binaryContainer; + + InfopointProcessor(DataBuilder dataBuilder) { + this.dataBuilder = dataBuilder; + this.binaryContainer = dataBuilder.getBinaryContainer(); + } + + /** + * Parse an {@link Infopoint} generated by the compiler and create all needed binary section + * constructs. + * + * @param methodInfo compiled method info + * @param info info point being processed + */ + void process(CompiledMethodInfo methodInfo, Infopoint info) { + switch (info.reason) { + case CALL: + // All calls in compiled code need a symbol and relocation entry. + processCallInfoPoint(methodInfo, (Call) info); + break; + case SAFEPOINT: + case IMPLICIT_EXCEPTION: + case METHOD_START: + case METHOD_END: + case BYTECODE_POSITION: + break; + default: + throw new InternalError("Unknown info point reason: " + info.reason); + } + if (info.debugInfo == null) return; + BytecodePosition bcp = info.debugInfo.getBytecodePosition(); + if (bcp == null) return; + recordScopeKlasses(methodInfo, bcp, info.debugInfo.getVirtualObjectMapping()); + } + + private void recordScopeKlasses(CompiledMethodInfo methodInfo, BytecodePosition bcp, VirtualObject[] vos) { + BytecodePosition caller = bcp.getCaller(); + if (caller != null) { + recordScopeKlasses(methodInfo, caller, vos); + } + + HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod)bcp.getMethod(); + HotSpotResolvedObjectType klass = m.getDeclaringClass(); + methodInfo.addDependentKlassData(binaryContainer, klass); + + if (vos == null) return; + + for (VirtualObject vo : vos) { + HotSpotResolvedObjectType vk = (HotSpotResolvedObjectType)vo.getType(); + methodInfo.addDependentKlassData(binaryContainer, vk); + } + + } + + /** + * Process Call info points in Graal generated compilation result. We want to create one of the + * following relocations: .text -> .hotspot.plt.linkage - Java method to Java method call .text + * -> .text - Java method / Graal stub to Graal stub call .text -> .plt - Java method / Graal + * stub to VM method call. + * + * @param methodInfo compiled method info + * @param call call + */ + private void processCallInfoPoint(CompiledMethodInfo methodInfo, Call call) { + CallSiteRelocationInfo callSiteRelocation = getCallSiteRelocationInfo(call); + CallSiteRelocationSymbol callSiteRelocationSymbol = getCallSiteRelocationSymbol(methodInfo, call, callSiteRelocation); + + Relocation relocation = new Relocation(methodInfo.getTextSectionOffset() + call.pcOffset, callSiteRelocation.type, call.size, binaryContainer.getCodeContainer(), + callSiteRelocationSymbol.symbol); + binaryContainer.addRelocation(relocation); + } + + /** + * Get information about the call site. Name of the callee and relocation call type. + */ + private CallSiteRelocationInfo getCallSiteRelocationInfo(Call call) { + InvokeTarget callTarget = call.target; + if (callTarget instanceof HotSpotResolvedJavaMethod) { + return new JavaCallSiteRelocationInfo(call, (HotSpotResolvedJavaMethod) callTarget); + } else if (callTarget instanceof HotSpotForeignCallLinkage) { + return new ForeignCallSiteRelocationInfo(call, (HotSpotForeignCallLinkage) callTarget, dataBuilder); + } else { + throw new InternalError("Unhandled call type found in infopoint: " + callTarget); + } + } + + /** + * Return a relocation symbol for the given call site. + */ + private CallSiteRelocationSymbol getCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation) { + switch (callSiteRelocation.type) { + case STUB_CALL_DIRECT: + return new StubDirectCallSiteRelocationSymbol(callSiteRelocation, binaryContainer); + case FOREIGN_CALL_INDIRECT_GOT: + return new ForeignGotCallSiteRelocationSymbol(mi, call, callSiteRelocation, dataBuilder); + case FOREIGN_CALL_DIRECT: + case FOREIGN_CALL_DIRECT_FAR: + case FOREIGN_CALL_INDIRECT: + return new ForeignCallSiteRelocationSymbol(callSiteRelocation, binaryContainer); + default: + return new JavaCallSiteRelocationSymbol(mi, call, callSiteRelocation, binaryContainer); + } + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InstructionDecoder.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InstructionDecoder.java new file mode 100644 index 00000000000..979e0cb2ed7 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InstructionDecoder.java @@ -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; + +import jdk.tools.jaotc.amd64.AMD64InstructionDecoder; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.TargetDescription; + +public abstract class InstructionDecoder { + + public static InstructionDecoder getInstructionDecoder(TargetDescription target) { + Architecture architecture = target.arch; + if (architecture instanceof AMD64) { + return new AMD64InstructionDecoder(target); + } else { + throw new InternalError("Unsupported architecture " + architecture); + } + } + + public abstract void decodePosition(final byte[] code, int pcOffset); + + public abstract int currentEndOfInstruction(); + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java new file mode 100644 index 00000000000..cd2db80fb5e --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java @@ -0,0 +1,41 @@ +/* + * 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 jdk.tools.jaotc.binformat.Relocation.RelocType; + +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; + +/** + * This is a Java call site. Get the Java method name and correct call relocation type. All static + * Java calls should be direct. All virtual Java calls should be indirect. + */ +final class JavaCallSiteRelocationInfo extends CallSiteRelocationInfo { + + public JavaCallSiteRelocationInfo(Call call, HotSpotResolvedJavaMethod callTarget) { + super(MiscUtils.uniqueMethodName(callTarget), call.direct ? RelocType.JAVA_CALL_DIRECT : RelocType.JAVA_CALL_INDIRECT); + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java new file mode 100644 index 00000000000..a14049dd87f --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java @@ -0,0 +1,130 @@ +/* + * 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 jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.Symbol; +import jdk.tools.jaotc.CompiledMethodInfo.StubInformation; + +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; + +/** + * Symbol for a regular Java call. This method also creates additional relocations for {@code .plt} + * to {@code .got} and {@code .got} to {@code .plt}. + */ +final class JavaCallSiteRelocationSymbol extends CallSiteRelocationSymbol { + + private static final byte[] zeroSlot = new byte[8]; + private static final byte[] minusOneSlot = {-1, -1, -1, -1, -1, -1, -1, -1}; + + public JavaCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) { + super(createPltEntrySymbol(binaryContainer, mi, call, callSiteRelocation)); + StubInformation stub = getStub(mi, call); + addRelocations(mi, stub, binaryContainer, call, callSiteRelocation); + } + + /** + * Returns a unique symbol name with the {@code suffix} appended. + */ + private static String relocationSymbolName(String suffix, CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation) { + return "M" + mi.getCodeId() + "_" + call.pcOffset + "_" + callSiteRelocation.targetSymbol + "_" + suffix; + } + + private static Symbol createPltEntrySymbol(BinaryContainer binaryContainer, CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation) { + String symbolName = relocationSymbolName("plt.entry", mi, call, callSiteRelocation); + StubInformation stub = getStub(mi, call); + return createCodeContainerSymbol(binaryContainer, symbolName, stub.getOffset()); + } + + private static StubInformation getStub(CompiledMethodInfo mi, Call call) { + HotSpotResolvedJavaMethod callTarget = (HotSpotResolvedJavaMethod) call.target; + String callTargetSymbol = MiscUtils.uniqueMethodName(callTarget) + ".at." + call.pcOffset; + return mi.getStubFor(callTargetSymbol); + } + + /** + * Add all the required relocations. + */ + private static void addRelocations(CompiledMethodInfo mi, StubInformation stub, BinaryContainer binaryContainer, Call call, CallSiteRelocationInfo callSiteRelocation) { + final boolean isVirtualCall = MiscUtils.isVirtualCall(mi, call); + + final int gotStartOffset = binaryContainer.appendExtLinkageGotBytes(zeroSlot, 0, zeroSlot.length); + if (isVirtualCall) { + // Nothing. + } else { + // For c2i stub we need slot with -1 value. + binaryContainer.appendExtLinkageGotBytes(minusOneSlot, 0, minusOneSlot.length); + } + + // Add relocation to GOT cell for call resolution jump. + String gotSymbolName = "got." + getResolveSymbolName(binaryContainer, mi, call); + Symbol gotSymbol = binaryContainer.getGotSymbol(gotSymbolName); + addExternalPltToGotRelocation(binaryContainer, gotSymbol, stub.getResolveJumpOffset()); + + // Add relocation to resolve call jump instruction address for GOT cell. + String pltJmpSymbolName = relocationSymbolName("plt.jmp", mi, call, callSiteRelocation); + addCodeContainerRelocation(binaryContainer, pltJmpSymbolName, stub.getResolveJumpStart(), gotStartOffset); + + // Add relocation to GOT cell for dispatch jump. + String gotEntrySymbolName = relocationSymbolName("got.entry", mi, call, callSiteRelocation); + addExtLinkageGotContainerRelocation(binaryContainer, gotEntrySymbolName, gotStartOffset, stub.getDispatchJumpOffset()); + + // Virtual call needs initial -1 value. + byte[] slot = isVirtualCall ? minusOneSlot : zeroSlot; + final int gotMetaOffset = binaryContainer.appendMetaspaceGotBytes(slot, 0, slot.length); + + // Add relocation to GOT cell for move instruction (Klass* for virtual, Method* otherwise). + String gotMoveSymbolName = relocationSymbolName("got.move", mi, call, callSiteRelocation); + addMetaspaceGotRelocation(binaryContainer, gotMoveSymbolName, gotMetaOffset, stub.getMovOffset()); + + if (isVirtualCall) { + // Nothing. + } else { + // Add relocation to GOT cell for c2i adapter jump. + String gotC2ISymbolName = relocationSymbolName("got.c2i", mi, call, callSiteRelocation); + addExtLinkageGotContainerRelocation(binaryContainer, gotC2ISymbolName, gotStartOffset + 8, stub.getC2IJumpOffset()); + } + } + + /** + * Returns the name of the resolve method for this particular call. + */ + private static String getResolveSymbolName(BinaryContainer binaryContainer, CompiledMethodInfo mi, Call call) { + String resolveSymbolName; + if (MiscUtils.isStaticCall(call)) { + resolveSymbolName = binaryContainer.getResolveStaticEntrySymbolName(); + } else if (MiscUtils.isSpecialCall(call)) { + resolveSymbolName = binaryContainer.getResolveOptVirtualEntrySymbolName(); + } else if (MiscUtils.isOptVirtualCall(mi, call)) { + resolveSymbolName = binaryContainer.getResolveOptVirtualEntrySymbolName(); + } else if (MiscUtils.isVirtualCall(mi, call)) { + resolveSymbolName = binaryContainer.getResolveVirtualEntrySymbolName(); + } else { + throw new InternalError("Unknown call type in " + mi.asTag() + " @ " + call.pcOffset + " for call" + call.target); + } + return resolveSymbolName; + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java new file mode 100644 index 00000000000..908d5b03ef0 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java @@ -0,0 +1,45 @@ +/* + * 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 jdk.vm.ci.hotspot.HotSpotCompiledCode; + +public interface JavaMethodInfo { + + /** + * @return unique symbol name for this method. + */ + String getSymbolName(); + + /** + * Name a java method with J.L.S. class name and signature. + * + * @return unique name for this method including class and signature + */ + String getNameAndSignature(); + + HotSpotCompiledCode compiledCode(CompilationResult result); + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java new file mode 100644 index 00000000000..5885deaa1fd --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java @@ -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; + +public interface LogPrinter { + void printInfo(String s); + + void printlnVerbose(String s); + + void printlnInfo(String s); + + void printError(String s); +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java new file mode 100644 index 00000000000..a1257b7a013 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java @@ -0,0 +1,767 @@ +/* + * 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 static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryUsage; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +import jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.ByteContainer; +import jdk.tools.jaotc.collect.ClassCollector; +import jdk.tools.jaotc.utils.Timer; + +import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.HotSpotHostBackend; +import org.graalvm.compiler.runtime.RuntimeProvider; + +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.runtime.JVMCI; + +public class Main implements LogPrinter { + static { + GeneratePIC.setValue(true); + ImmutableCode.setValue(true); + } + + static class BadArgs extends Exception { + private static final long serialVersionUID = 1L; + final String key; + final Object[] args; + boolean showUsage; + + BadArgs(String key, Object... args) { + super(MessageFormat.format(key, args)); + this.key = key; + this.args = args; + } + + BadArgs showUsage(boolean b) { + showUsage = b; + return this; + } + } + + abstract static class Option { + final String help; + final boolean hasArg; + final String[] aliases; + + Option(String help, boolean hasArg, String... aliases) { + this.help = help; + this.hasArg = hasArg; + this.aliases = aliases; + } + + boolean isHidden() { + return false; + } + + boolean matches(String opt) { + for (String a : aliases) { + if (a.equals(opt)) { + return true; + } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) { + return true; + } + } + return false; + } + + boolean ignoreRest() { + return false; + } + + abstract void process(Main task, String opt, String arg) throws BadArgs; + } + + static Option[] recognizedOptions = {new Option(" --module Module to compile", true, "--module") { + @Override + void process(Main task, String opt, String arg) { + task.options.module = arg; + } + }, new Option(" --module-path Specify where to find module to compile", true, "--module-path") { + @Override + void process(Main task, String opt, String arg) { + task.options.modulepath = arg; + } + }, new Option(" --output Output file name", true, "--output") { + @Override + void process(Main task, String opt, String arg) { + String name = arg; + if (name.endsWith(".so")) { + name = name.substring(0, name.length() - ".so".length()); + } + task.options.outputName = name; + } + }, new Option(" --compile-commands Name of file with compile commands", true, "--compile-commands") { + @Override + void process(Main task, String opt, String arg) { + task.options.methodList = arg; + } + }, new Option(" --compile-for-tiered Generated profiling code for tiered compilation", false, "--compile-for-tiered") { + @Override + void process(Main task, String opt, String arg) { + TieredAOT.setValue(true); + } + }, new Option(" --classpath Specify where to find user class files", true, "--classpath", "--class-path") { + @Override + void process(Main task, String opt, String arg) { + task.options.classpath = arg; + } + }, new Option(" --threads Number of compilation threads to be used", true, "--threads") { + @Override + void process(Main task, String opt, String arg) { + int threads = Integer.parseInt(arg); + final int available = Runtime.getRuntime().availableProcessors(); + if (threads <= 0) { + task.warning("invalid number of threads specified: {0}, using: {1}", threads, available); + threads = available; + } + if (threads > available) { + task.warning("too many threads specified: {0}, limiting to: {1}", threads, available); + } + task.options.threads = Integer.min(threads, available); + } + }, new Option(" --ignore-errors Ignores all exceptions thrown during class loading", false, "--ignore-errors") { + @Override + void process(Main task, String opt, String arg) { + task.options.ignoreClassLoadingErrors = true; + } + }, new Option(" --exit-on-error Exit on compilation errors", false, "--exit-on-error") { + @Override + void process(Main task, String opt, String arg) { + task.options.exitOnError = true; + } + }, new Option(" --info Print information during compilation", false, "--info") { + @Override + void process(Main task, String opt, String arg) throws BadArgs { + task.options.info = true; + } + }, new Option(" --verbose Print verbose information", false, "--verbose") { + @Override + void process(Main task, String opt, String arg) throws BadArgs { + task.options.info = true; + task.options.verbose = true; + } + }, new Option(" --debug Print debug information", false, "--debug") { + @Override + void process(Main task, String opt, String arg) throws BadArgs { + task.options.info = true; + task.options.verbose = true; + task.options.debug = true; + } + }, new Option(" --help Print this usage message", false, "--help") { + @Override + void process(Main task, String opt, String arg) { + task.options.help = true; + } + }, new Option(" --version Version information", false, "--version") { + @Override + void process(Main task, String opt, String arg) { + task.options.version = true; + } + }, new Option(" -J Pass directly to the runtime system", false, "-J") { + @Override + void process(Main task, String opt, String arg) { + } + }}; + + public static class Options { + public List files = new LinkedList<>(); + public String module = null; + public String modulepath = "modules"; + public String outputName = "unnamed"; + public String methodList; + public String classpath = "."; + + /** + * We don't see scaling beyond 16 threads. + */ + private static final int COMPILER_THREADS = 16; + + int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors()); + + public boolean ignoreClassLoadingErrors; + public boolean exitOnError; + boolean info; + boolean verbose; + boolean debug; + boolean help; + boolean version; + } + + /* package */final Options options = new Options(); + + /** + * Logfile. + */ + private static FileWriter logFile = null; + + private static final int EXIT_OK = 0; // No errors. + private static final int EXIT_CMDERR = 2; // Bad command-line arguments and/or switches. + private static final int EXIT_ABNORMAL = 4; // Terminated abnormally. + + private static final String PROGNAME = "jaotc"; + + private static final String JVM_VERSION = System.getProperty("java.runtime.version"); + + public static void main(String[] args) throws Exception { + Main t = new Main(); + final int exitCode = t.run(args); + System.exit(exitCode); + } + + private int run(String[] args) { + if (log == null) { + log = new PrintWriter(System.out); + } + + try { + handleOptions(args); + if (options.help) { + showHelp(); + return EXIT_OK; + } + if (options.version) { + showVersion(); + return EXIT_OK; + } + + printlnInfo("Compiling " + options.outputName + "..."); + final long start = System.currentTimeMillis(); + run(); + final long end = System.currentTimeMillis(); + printlnInfo("Total time: " + (end - start) + " ms"); + + return EXIT_OK; + } catch (BadArgs e) { + reportError(e.key, e.args); + if (e.showUsage) { + showUsage(); + } + return EXIT_CMDERR; + } catch (Exception e) { + e.printStackTrace(); + return EXIT_ABNORMAL; + } finally { + log.flush(); + } + } + + private static String humanReadableByteCount(long bytes) { + int unit = 1024; + + if (bytes < unit) { + return bytes + " B"; + } + + int exp = (int) (Math.log(bytes) / Math.log(unit)); + char pre = "KMGTPE".charAt(exp - 1); + return String.format("%.1f %cB", bytes / Math.pow(unit, exp), pre); + } + + void printMemoryUsage() { + if (options.verbose) { + MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted(); + log.format(" [used: %-7s, comm: %-7s, freeRatio ~= %.1f%%]", + humanReadableByteCount(memusage.getUsed()), + humanReadableByteCount(memusage.getCommitted()), + freeratio * 100); + } + } + + @SuppressWarnings("try") + private void run() throws Exception { + openLog(); + + try { + CompilationSpec compilationRestrictions = collectSpecifiedMethods(); + + Set> classesToCompile; + + try (Timer t = new Timer(this, "")) { + ClassCollector collector = new ClassCollector(this.options, this); + classesToCompile = collector.collectClassesToCompile(); + printInfo(classesToCompile.size() + " classes found"); + } + + GraalJVMCICompiler graalCompiler = (GraalJVMCICompiler) JVMCI.getRuntime().getCompiler(); + HotSpotGraalRuntimeProvider runtime = (HotSpotGraalRuntimeProvider) graalCompiler.getGraalRuntime(); + HotSpotHostBackend backend = (HotSpotHostBackend) runtime.getCapability(RuntimeProvider.class).getHostBackend(); + MetaAccessProvider metaAccess = backend.getProviders().getMetaAccess(); + GraalFilters filters = new GraalFilters(metaAccess); + + List classes; + + try (Timer t = new Timer(this, "")) { + classes = collectMethodsToCompile(classesToCompile, compilationRestrictions, filters, metaAccess); + } + + // Free memory! + try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { + printMemoryUsage(); + compilationRestrictions = null; + classesToCompile = null; + System.gc(); + } + + AOTBackend aotBackend = new AOTBackend(this, backend, filters); + AOTCompiler compiler = new AOTCompiler(this, aotBackend, options.threads); + classes = compiler.compileClasses(classes); + + // Free memory! + try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { + printMemoryUsage(); + aotBackend = null; + compiler = null; + System.gc(); + } + + BinaryContainer binaryContainer = new BinaryContainer(runtime.getVMConfig(), JVM_VERSION); + DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer); + dataBuilder.prepareData(); + + // Print information about section sizes + printContainerInfo(binaryContainer.getHeaderContainer().getContainer()); + printContainerInfo(binaryContainer.getConfigContainer()); + printContainerInfo(binaryContainer.getKlassesOffsetsContainer()); + printContainerInfo(binaryContainer.getMethodsOffsetsContainer()); + printContainerInfo(binaryContainer.getKlassesDependenciesContainer()); + printContainerInfo(binaryContainer.getStubsOffsetsContainer()); + printContainerInfo(binaryContainer.getMethodMetadataContainer()); + printContainerInfo(binaryContainer.getCodeContainer()); + printContainerInfo(binaryContainer.getCodeSegmentsContainer()); + printContainerInfo(binaryContainer.getConstantDataContainer()); + printContainerInfo(binaryContainer.getMetaspaceGotContainer()); + printContainerInfo(binaryContainer.getMetadataGotContainer()); + printContainerInfo(binaryContainer.getMethodStateContainer()); + printContainerInfo(binaryContainer.getOopGotContainer()); + printContainerInfo(binaryContainer.getMetaspaceNamesContainer()); + + // Free memory! + try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { + printMemoryUsage(); + backend = null; + for (AOTCompiledClass aotCompClass : classes) { + aotCompClass.clear(); + } + classes.clear(); + classes = null; + dataBuilder = null; + binaryContainer.freeMemory(); + System.gc(); + } + + String objectFileName = options.outputName + ".o"; + String libraryFileName = options.outputName + ".so"; + + try (Timer t = new Timer(this, "Creating binary: " + objectFileName)) { + binaryContainer.createBinary(objectFileName, JVM_VERSION); + } + + // Free memory! + try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { + printMemoryUsage(); + binaryContainer = null; + System.gc(); + } + + try (Timer t = new Timer(this, "Creating shared library: " + libraryFileName)) { + Process p = Runtime.getRuntime().exec("ld -shared -z noexecstack -o " + libraryFileName + " " + objectFileName); + final int exitCode = p.waitFor(); + if (exitCode != 0) { + InputStream stderr = p.getErrorStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(stderr)); + Stream lines = br.lines(); + StringBuilder sb = new StringBuilder(); + lines.iterator().forEachRemaining(e -> sb.append(e)); + throw new InternalError(sb.toString()); + } + File objFile = new File(objectFileName); + if (objFile.exists()) { + if (!objFile.delete()) { + throw new InternalError("Failed to delete " + objectFileName + " file"); + } + } + // Make non-executable for all. + File libFile = new File(libraryFileName); + if (libFile.exists()) { + if (!libFile.setExecutable(false, false)) { + throw new InternalError("Failed to change attribute for " + libraryFileName + " file"); + } + } + } + + printVerbose("Final memory "); + printMemoryUsage(); + printlnVerbose(""); + + } finally { + closeLog(); + } + } + + private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions, GraalFilters filters) { + for (ResolvedJavaMethod m : methods) { + addMethod(aotClass, m, compilationRestrictions, filters); + } + } + + private void addMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method, CompilationSpec compilationRestrictions, GraalFilters filters) { + // Don't compile native or abstract methods. + if (!method.hasBytecodes()) { + return; + } + if (!compilationRestrictions.shouldCompileMethod(method)) { + return; + } + if (!filters.shouldCompileMethod(method)) { + return; + } + + aotClass.addMethod(method); + printlnVerbose(" added " + method.getName() + method.getSignature().toMethodDescriptor()); + } + + private void printContainerInfo(ByteContainer container) { + printlnVerbose(container.getContainerName() + ": " + container.getByteStreamSize() + " bytes"); + } + + PrintWriter log; + + private void handleOptions(String[] args) throws BadArgs { + if (args.length == 0) { + options.help = true; + return; + } + + // Make checkstyle happy. + int i = 0; + for (; i < args.length; i++) { + String arg = args[i]; + + if (arg.charAt(0) == '-') { + Option option = getOption(arg); + String param = null; + + if (option.hasArg) { + if (arg.startsWith("--") && arg.indexOf('=') > 0) { + param = arg.substring(arg.indexOf('=') + 1, arg.length()); + } else if (i + 1 < args.length) { + param = args[++i]; + } + + if (param == null || param.isEmpty() || param.charAt(0) == '-') { + throw new BadArgs("missing argument for option: {0}", arg).showUsage(true); + } + } + + option.process(this, arg, param); + + if (option.ignoreRest()) { + break; + } + } else { + options.files.add(arg); + } + } + } + + private static Option getOption(String name) throws BadArgs { + for (Option o : recognizedOptions) { + if (o.matches(name)) { + return o; + } + } + throw new BadArgs("unknown option: {0}", name).showUsage(true); + } + + public void printInfo(String message) { + if (options.info) { + log.print(message); + log.flush(); + } + } + + public void printlnInfo(String message) { + if (options.info) { + log.println(message); + log.flush(); + } + } + + public void printVerbose(String message) { + if (options.verbose) { + log.print(message); + log.flush(); + } + } + + public void printlnVerbose(String message) { + if (options.verbose) { + log.println(message); + log.flush(); + } + } + + public void printDebug(String message) { + if (options.debug) { + log.print(message); + log.flush(); + } + } + + public void printlnDebug(String message) { + if (options.debug) { + log.println(message); + log.flush(); + } + } + + public void printError(String message) { + log.println("Error: " + message); + log.flush(); + } + + private void reportError(String key, Object... args) { + printError(MessageFormat.format(key, args)); + } + + private void warning(String key, Object... args) { + log.println("Warning: " + MessageFormat.format(key, args)); + log.flush(); + } + + private void showUsage() { + log.println("Usage: " + PROGNAME + " list..."); + log.println("use --help for a list of possible options"); + } + + private void showHelp() { + log.println("Usage: " + PROGNAME + " <--module name> | "); + log.println(); + log.println(" list A list of class files, jar files or directories which"); + log.println(" contains class files."); + log.println(); + log.println("where possible options include:"); + for (Option o : recognizedOptions) { + String name = o.aliases[0].substring(1); // there must always be at least one name + name = name.charAt(0) == '-' ? name.substring(1) : name; + if (o.isHidden() || name.equals("h")) { + continue; + } + log.println(o.help); + } + } + + private void showVersion() { + log.println(PROGNAME + " " + JVM_VERSION); + } + + /** + * Collect all method we should compile. + * + * @return array list of AOT classes which have compiled methods. + */ + private List collectMethodsToCompile(Set> classesToCompile, CompilationSpec compilationRestrictions, GraalFilters filters, MetaAccessProvider metaAccess) { + int total = 0; + int count = 0; + List classes = new ArrayList<>(); + + for (Class c : classesToCompile) { + ResolvedJavaType resolvedJavaType = metaAccess.lookupJavaType(c); + if (filters.shouldCompileAnyMethodInClass(resolvedJavaType)) { + AOTCompiledClass aotClass = new AOTCompiledClass(resolvedJavaType); + printlnVerbose(" Scanning " + c.getName()); + + // Constructors + try { + ResolvedJavaMethod[] ctors = resolvedJavaType.getDeclaredConstructors(); + addMethods(aotClass, ctors, compilationRestrictions, filters); + total += ctors.length; + } catch (Throwable e) { + // If we are running in JCK mode we ignore all exceptions. + if (options.ignoreClassLoadingErrors) { + printError(c.getName() + ": " + e); + } else { + throw new InternalError(e); + } + } + + // Methods + try { + ResolvedJavaMethod[] methods = resolvedJavaType.getDeclaredMethods(); + addMethods(aotClass, methods, compilationRestrictions, filters); + total += methods.length; + } catch (Throwable e) { + // If we are running in JCK mode we ignore all exceptions. + if (options.ignoreClassLoadingErrors) { + printError(c.getName() + ": " + e); + } else { + throw new InternalError(e); + } + } + + // Class initializer + try { + ResolvedJavaMethod clinit = resolvedJavaType.getClassInitializer(); + if (clinit != null) { + addMethod(aotClass, clinit, compilationRestrictions, filters); + total++; + } + } catch (Throwable e) { + // If we are running in JCK mode we ignore all exceptions. + if (options.ignoreClassLoadingErrors) { + printError(c.getName() + ": " + e); + } else { + throw new InternalError(e); + } + } + + // Found any methods to compile? Add the class. + if (aotClass.hasMethods()) { + classes.add(aotClass); + count += aotClass.getMethodCount(); + } + } + } + printInfo(total + " methods total, " + count + " methods to compile"); + return classes; + } + + /** + * If a file with compilation limitations is specified using the java property + * jdk.tools.jaotc.compile.method.list, read the file's contents and collect the restrictions. + */ + private CompilationSpec collectSpecifiedMethods() { + CompilationSpec compilationRestrictions = new CompilationSpec(); + String methodListFileName = options.methodList; + + if (methodListFileName != null && !methodListFileName.equals("")) { + try { + FileReader methListFile = new FileReader(methodListFileName); + BufferedReader readBuf = new BufferedReader(methListFile); + String line = null; + while ((line = readBuf.readLine()) != null) { + String trimmedLine = line.trim(); + if (!trimmedLine.startsWith("#")) { + String[] components = trimmedLine.split(" "); + if (components.length == 2) { + String directive = components[0]; + String pattern = components[1]; + switch (directive) { + case "compileOnly": + compilationRestrictions.addCompileOnlyPattern(pattern); + break; + case "exclude": + compilationRestrictions.addExcludePattern(pattern); + break; + default: + System.out.println("Unrecognized command " + directive + ". Ignoring\n\t" + line + "\n encountered in " + methodListFileName); + } + } else { + if (!trimmedLine.equals("")) { + System.out.println("Ignoring malformed line:\n\t " + line + "\n"); + } + } + } + } + readBuf.close(); + } catch (FileNotFoundException e) { + throw new InternalError("Unable to open method list file: " + methodListFileName, e); + } catch (IOException e) { + throw new InternalError("Unable to read method list file: " + methodListFileName, e); + } + } + + return compilationRestrictions; + } + + private static void openLog() { + int v = Integer.getInteger("jdk.tools.jaotc.logCompilation", 0); + if (v == 0) { + logFile = null; + return; + } + // Create log file in current directory + String fileName = "aot_compilation" + new Date().getTime() + ".log"; + Path logFilePath = Paths.get("./", fileName); + String logFileName = logFilePath.toString(); + try { + // Create file to which we do not append + logFile = new FileWriter(logFileName, false); + } catch (IOException e) { + System.out.println("Unable to open logfile :" + logFileName + "\nNo logs will be created"); + logFile = null; + } + } + + public static void writeLog(String str) { + if (logFile != null) { + try { + logFile.write(str + "\n"); + logFile.flush(); + } catch (IOException e) { + // Print to console + System.out.println(str + "\n"); + } + } + } + + public static void closeLog() { + if (logFile != null) { + try { + logFile.close(); + } catch (IOException e) { + // Do nothing + } + } + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java new file mode 100644 index 00000000000..4bbd4665434 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java @@ -0,0 +1,69 @@ +/* + * 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 jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; + +/** + * Constants used to mark special positions in code being installed into the code cache by Graal C++ + * code. + */ +enum MarkId { + VERIFIED_ENTRY("CodeInstaller::VERIFIED_ENTRY"), + UNVERIFIED_ENTRY("CodeInstaller::UNVERIFIED_ENTRY"), + OSR_ENTRY("CodeInstaller::OSR_ENTRY"), + EXCEPTION_HANDLER_ENTRY("CodeInstaller::EXCEPTION_HANDLER_ENTRY"), + DEOPT_HANDLER_ENTRY("CodeInstaller::DEOPT_HANDLER_ENTRY"), + INVOKEINTERFACE("CodeInstaller::INVOKEINTERFACE"), + INVOKEVIRTUAL("CodeInstaller::INVOKEVIRTUAL"), + INVOKESTATIC("CodeInstaller::INVOKESTATIC"), + INVOKESPECIAL("CodeInstaller::INVOKESPECIAL"), + INLINE_INVOKE("CodeInstaller::INLINE_INVOKE"), + POLL_NEAR("CodeInstaller::POLL_NEAR"), + POLL_RETURN_NEAR("CodeInstaller::POLL_RETURN_NEAR"), + POLL_FAR("CodeInstaller::POLL_FAR"), + POLL_RETURN_FAR("CodeInstaller::POLL_RETURN_FAR"), + CARD_TABLE_ADDRESS("CodeInstaller::CARD_TABLE_ADDRESS"), + HEAP_TOP_ADDRESS("CodeInstaller::HEAP_TOP_ADDRESS"), + HEAP_END_ADDRESS("CodeInstaller::HEAP_END_ADDRESS"), + NARROW_KLASS_BASE_ADDRESS("CodeInstaller::NARROW_KLASS_BASE_ADDRESS"), + CRC_TABLE_ADDRESS("CodeInstaller::CRC_TABLE_ADDRESS"), + LOG_OF_HEAP_REGION_GRAIN_BYTES("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES"), + INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED"); + + private final int value; + + private MarkId(String name) { + this.value = (int) (long) HotSpotJVMCIRuntime.runtime().getConfigStore().getConstants().get(name); + } + + public static MarkId getEnum(int value) { + for (MarkId e : values()) { + if (e.value == value) { + return e; + } + } + throw new InternalError("Unknown enum value: " + value); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java new file mode 100644 index 00000000000..1e1944bc274 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java @@ -0,0 +1,117 @@ +/* + * 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 jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.Relocation; +import jdk.tools.jaotc.binformat.Relocation.RelocType; +import jdk.tools.jaotc.binformat.Symbol; + +import jdk.vm.ci.code.site.Mark; + +class MarkProcessor { + + private final BinaryContainer binaryContainer; + + MarkProcessor(DataBuilder dataBuilder) { + binaryContainer = dataBuilder.getBinaryContainer(); + } + + /** + * Parse a {@link Mark} generated by the compiler and create all needed binary section + * constructs. + * + * @param methodInfo compiled method info + * @param mark mark being processed + */ + void process(CompiledMethodInfo methodInfo, Mark mark) { + MarkId markId = MarkId.getEnum((int) mark.id); + switch (markId) { + case EXCEPTION_HANDLER_ENTRY: + case DEOPT_HANDLER_ENTRY: + break; + case POLL_FAR: + case POLL_RETURN_FAR: + case CARD_TABLE_ADDRESS: + case HEAP_TOP_ADDRESS: + case HEAP_END_ADDRESS: + case NARROW_KLASS_BASE_ADDRESS: + case CRC_TABLE_ADDRESS: + case LOG_OF_HEAP_REGION_GRAIN_BYTES: + case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED: + String vmSymbolName; + switch (markId) { + case POLL_FAR: + case POLL_RETURN_FAR: + vmSymbolName = binaryContainer.getPollingPageSymbolName(); + break; + case CARD_TABLE_ADDRESS: + vmSymbolName = binaryContainer.getCardTableAddressSymbolName(); + break; + case HEAP_TOP_ADDRESS: + vmSymbolName = binaryContainer.getHeapTopAddressSymbolName(); + break; + case HEAP_END_ADDRESS: + vmSymbolName = binaryContainer.getHeapEndAddressSymbolName(); + break; + case NARROW_KLASS_BASE_ADDRESS: + vmSymbolName = binaryContainer.getNarrowKlassBaseAddressSymbolName(); + break; + case CRC_TABLE_ADDRESS: + vmSymbolName = binaryContainer.getCrcTableAddressSymbolName(); + break; + case LOG_OF_HEAP_REGION_GRAIN_BYTES: + vmSymbolName = binaryContainer.getLogOfHeapRegionGrainBytesSymbolName(); + break; + case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED: + vmSymbolName = binaryContainer.getInlineContiguousAllocationSupportedSymbolName(); + break; + default: + throw new InternalError("Unhandled mark: " + mark); + } + String s = "got." + vmSymbolName; + Symbol gotSymbol = binaryContainer.getGotSymbol(s); + assert gotSymbol != null : " Processing Mark: Encountered undefined got symbol for " + mark; + final int textBaseOffset = methodInfo.getTextSectionOffset(); + final int textOffset = textBaseOffset + mark.pcOffset; + Relocation reloc = new Relocation(textOffset, RelocType.EXTERNAL_PLT_TO_GOT, 8, binaryContainer.getCodeContainer(), gotSymbol); + binaryContainer.addRelocation(reloc); + break; + case VERIFIED_ENTRY: + case UNVERIFIED_ENTRY: + case OSR_ENTRY: + case INVOKEINTERFACE: + case INVOKEVIRTUAL: + case INVOKESTATIC: + case INVOKESPECIAL: + case INLINE_INVOKE: + case POLL_NEAR: + case POLL_RETURN_NEAR: + // Nothing to do. + break; + default: + throw new InternalError("Unexpected mark found: " + mark); + } + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java new file mode 100644 index 00000000000..9a8726b0709 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java @@ -0,0 +1,243 @@ +/* + * 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 jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.ByteContainer; +import jdk.tools.jaotc.binformat.Symbol.Binding; +import jdk.tools.jaotc.binformat.Symbol.Kind; +import jdk.tools.jaotc.binformat.GotSymbol; +import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData; +import jdk.tools.jaotc.utils.NativeOrderOutputStream; +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; + +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.code.site.DataPatch; +import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.code.site.Mark; +import jdk.vm.ci.hotspot.HotSpotCompiledCode; +import jdk.vm.ci.hotspot.HotSpotMetaData; + +class MetadataBuilder { + + private final DataBuilder dataBuilder; + + private final BinaryContainer binaryContainer; + + MetadataBuilder(DataBuilder dataBuilder) { + this.dataBuilder = dataBuilder; + this.binaryContainer = dataBuilder.getBinaryContainer(); + } + + /** + * Process compiled methods and create method metadata. + */ + void processMetadata(List classes, AOTCompiledClass stubCompiledCode) { + binaryContainer.getMethodMetadataContainer().createSymbol(0, Kind.OBJECT, Binding.LOCAL, 0, "metaStart"); + + for (AOTCompiledClass c : classes) { + processMetadataClass(c); + } + processMetadataClass(stubCompiledCode); + } + + private void processMetadataClass(AOTCompiledClass c) { + processInfopointsAndMarks(c); + createMethodMetadata(c); + } + + /** + * Add metadata for each of the compiled methods in {@code compiledClass} to read-only section + * of {@code binaryContainer}. + * + * @param compiledClass AOT Graal compilation result + */ + private void createMethodMetadata(AOTCompiledClass compiledClass) { + HotSpotGraalRuntimeProvider runtime = dataBuilder.getBackend().getRuntime(); + ByteContainer methodMetadataContainer = binaryContainer.getMethodMetadataContainer(); + + // For each of the compiled java methods, create records holding information about them. + for (CompiledMethodInfo methodInfo : compiledClass.getCompiledMethods()) { + // Get the current offset in the methodmetadata container. + final int startOffset = methodMetadataContainer.getByteStreamSize(); + assert startOffset % 8 == 0 : "Must be aligned on 8"; + + methodInfo.setMetadataOffset(startOffset); + + HotSpotCompiledCode compiledMethod = methodInfo.compiledCode(); + // pc and scope description + HotSpotMetaData metaData = new HotSpotMetaData(runtime.getTarget(), compiledMethod); + + byte[] pcDesc = metaData.pcDescBytes(); + byte[] scopeDesc = metaData.scopesDescBytes(); + byte[] relocationInfo = metaData.relocBytes(); + byte[] oopMapInfo = metaData.oopMaps(); + + // create a global symbol at this position for this method + NativeOrderOutputStream metadataStream = new NativeOrderOutputStream(); + + // get the code size + int codeSize = methodInfo.getCodeSize(); + + // get code offsets + CodeOffsets co = CodeOffsets.buildFrom(methodInfo.getCompilationResult().getMarks()); + int unverifiedEntry = co.entry(); + int verifiedEntry = co.verifiedEntry(); + int exceptionHandler = co.exceptionHandler(); + int deoptHandler = co.deoptHandler(); + int frameSize = methodInfo.getCompilationResult().getTotalFrameSize(); + StackSlot deoptRescueSlot = methodInfo.getCompilationResult().getCustomStackArea(); + int origPcOffset = deoptRescueSlot != null ? deoptRescueSlot.getOffset(frameSize) : -1; + + // get stubs offset + int stubsOffset = methodInfo.getStubsOffset(); + + int offset = addMetadataEntries(binaryContainer, metaData, methodInfo); + methodInfo.setMetadataGotOffset(offset); + methodInfo.setMetadataGotSize(metaData.metadataEntries().length); + int unsafeAccess = methodInfo.getCompilationResult().hasUnsafeAccess() ? 1 : 0; + try { + // calculate total size of the container + NativeOrderOutputStream.PatchableInt totalSize = metadataStream.patchableInt(); + + // @formatter:off + metadataStream.putInt(codeSize). + putInt(unverifiedEntry). + putInt(verifiedEntry). + putInt(exceptionHandler). + putInt(deoptHandler). + putInt(stubsOffset). + putInt(frameSize). + putInt(origPcOffset). + putInt(unsafeAccess); + // @formatter:on + + NativeOrderOutputStream.PatchableInt pcDescOffset = metadataStream.patchableInt(); + NativeOrderOutputStream.PatchableInt scopeOffset = metadataStream.patchableInt(); + NativeOrderOutputStream.PatchableInt relocationOffset = metadataStream.patchableInt(); + NativeOrderOutputStream.PatchableInt exceptionOffset = metadataStream.patchableInt(); + NativeOrderOutputStream.PatchableInt oopMapOffset = metadataStream.patchableInt(); + metadataStream.align(8); + + pcDescOffset.set(metadataStream.position()); + metadataStream.put(pcDesc).align(8); + + scopeOffset.set(metadataStream.position()); + metadataStream.put(scopeDesc).align(8); + + relocationOffset.set(metadataStream.position()); + metadataStream.put(relocationInfo).align(8); + + exceptionOffset.set(metadataStream.position()); + metadataStream.put(metaData.exceptionBytes()).align(8); + + // oopmaps should be last + oopMapOffset.set(metadataStream.position()); + metadataStream.put(oopMapInfo).align(8); + + totalSize.set(metadataStream.position()); + + byte[] data = metadataStream.array(); + + methodMetadataContainer.appendBytes(data, 0, data.length); + } catch (Exception e) { + throw new InternalError("Exception occurred during compilation of " + methodInfo.getMethodInfo().getSymbolName(), e); + } + methodInfo.clearCompileData(); // Clear unused anymore compilation data + } + } + + private static int addMetadataEntries(BinaryContainer binaryContainer, HotSpotMetaData metaData, CompiledMethodInfo methodInfo) { + String[] metaDataEntries = metaData.metadataEntries(); + + if (metaDataEntries.length == 0) { + return 0; + } + + int metadataGotSlotsStart = binaryContainer.getMetadataGotContainer().getByteStreamSize(); // binaryContainer.reserveMetadataGOTSlots(metaDataEntries.length); + + for (int index = 0; index < metaDataEntries.length; index++) { + String name = metaDataEntries[index]; + addMetadataEntry(binaryContainer, name); + // Create GOT cells for klasses referenced in metadata + String klassName = name; + int len = name.length(); + 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; + klassName = name.substring(0, dotIndex); + } + // We should already have added entries for this klass + assert AOTCompiledClass.getAOTKlassData(klassName) != null; + assert methodInfo.getDependentKlassData(klassName) != null; + } + + return metadataGotSlotsStart; + } + + private static void addMetadataEntry(BinaryContainer binaryContainer, String name) { + int stringOffset = binaryContainer.addMetaspaceName(name); + binaryContainer.addMetadataGotEntry(stringOffset); + } + + /** + * Process {@link Infopoint}s, {@link Mark}s and {@link DataPatch}es generated by the compiler + * to create all needed binary section constructs. + * + * @param compiledClass compilation result + */ + private void processInfopointsAndMarks(AOTCompiledClass compiledClass) { + ArrayList compiledMethods = compiledClass.getCompiledMethods(); + + MarkProcessor markProcessor = new MarkProcessor(dataBuilder); + DataPatchProcessor dataPatchProcessor = new DataPatchProcessor(dataBuilder); + InfopointProcessor infopointProcessor = new InfopointProcessor(dataBuilder); + + for (CompiledMethodInfo methodInfo : compiledMethods) { + CompilationResult compilationResult = methodInfo.getCompilationResult(); + String targetSymbol = "state.M" + methodInfo.getCodeId(); + String gotName = "got." + targetSymbol; + GotSymbol symbol = binaryContainer.getMethodStateContainer().createGotSymbol(gotName); + assert (symbol.getIndex() == methodInfo.getCodeId()) : "wrong offset"; + + for (Infopoint infoPoint : compilationResult.getInfopoints()) { + infopointProcessor.process(methodInfo, infoPoint); + } + + for (Mark mark : compilationResult.getMarks()) { + markProcessor.process(methodInfo, mark); + } + + for (DataPatch dataPatch : compilationResult.getDataPatches()) { + dataPatchProcessor.process(methodInfo, dataPatch); + } + } + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MiscUtils.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MiscUtils.java new file mode 100644 index 00000000000..1503b9d0efe --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MiscUtils.java @@ -0,0 +1,103 @@ +/* + * 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.bytecode.Bytecodes; + +import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class MiscUtils { + + /** + * Name a java method with class and signature to make it unique. + * + * @param method to generate unique identifier for + * @return Unique name for this method including class and signature + **/ + public static String uniqueMethodName(ResolvedJavaMethod method) { + String className = method.getDeclaringClass().toClassName(); + String name = className + "." + method.getName() + method.getSignature().toMethodDescriptor(); + return name; + } + + public static boolean isStaticCall(Call call) { + if (isJavaCall(call)) { + return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESTATIC); + } + return false; + } + + public static boolean isSpecialCall(Call call) { + if (isJavaCall(call)) { + return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESPECIAL); + } + return false; + } + + private static boolean isInvokeVirtual(Call call) { + if (isJavaCall(call)) { + return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEVIRTUAL) || ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEINTERFACE); + } + return false; + } + + public static boolean isVirtualCall(CompiledMethodInfo methodInfo, Call call) { + return isInvokeVirtual(call) && !methodInfo.hasMark(call, MarkId.INVOKESPECIAL); + } + + public static boolean isOptVirtualCall(CompiledMethodInfo methodInfo, Call call) { + return isInvokeVirtual(call) && methodInfo.hasMark(call, MarkId.INVOKESPECIAL); + } + + private static boolean isJavaCall(Call call) { + // If there is no associated debug info return false + if (call.debugInfo == null) { + return false; + } + BytecodePosition bcpos = call.debugInfo.getBytecodePosition(); + ResolvedJavaMethod method = bcpos.getMethod(); + // If bytecode position indicates a special value (negative value) it is + // not a normal java call + if (bcpos.getBCI() < 0) { + return false; + } + // If there is no method associated with the debuginfo, return false + if (method == null) { + return false; + } + assert (method instanceof HotSpotResolvedJavaMethod) : "Not a resolved Java call"; + return true; + } + + private static byte getByteCode(Call call) { + ResolvedJavaMethod m = call.debugInfo.getBytecodePosition().getMethod(); + int callPosition = call.debugInfo.getBytecodePosition().getBCI(); + byte[] code = m.getCode(); + return code[callPosition]; + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java new file mode 100644 index 00000000000..50826f7e986 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java @@ -0,0 +1,39 @@ +/* + * 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 jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.Symbol.Binding; + +/** + * Call to a Graal stub, the symbol name should be direct. + */ +final class StubDirectCallSiteRelocationSymbol extends CallSiteRelocationSymbol { + + public StubDirectCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) { + super(binaryContainer.getSymbol(callSiteRelocation.targetSymbol)); + assert symbol != null && symbol.getBinding() == Binding.LOCAL : "Stub symbol must exist and must be LOCAL"; + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java new file mode 100644 index 00000000000..8ec0903911d --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java @@ -0,0 +1,119 @@ +/* + * 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.amd64; + +import static jdk.vm.ci.amd64.AMD64.rax; +import static jdk.vm.ci.amd64.AMD64.rbx; +import static jdk.vm.ci.amd64.AMD64.rip; + +import jdk.tools.jaotc.CompiledMethodInfo.StubInformation; +import jdk.tools.jaotc.ELFMacroAssembler; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; + +import jdk.vm.ci.code.TargetDescription; + +public final class AMD64ELFMacroAssembler extends AMD64MacroAssembler implements ELFMacroAssembler { + + private int currentEndOfInstruction; + + public AMD64ELFMacroAssembler(TargetDescription target) { + super(target); + } + + @Override + public int currentEndOfInstruction() { + return currentEndOfInstruction; + } + + @Override + public byte[] getPLTJumpCode() { + // The main dispatch instruction + // jmpq *0x00000000(%rip) + jmp(new AMD64Address(rip, 0)); + currentEndOfInstruction = position(); + + // Align to 8 bytes + align(8); + + return close(true); + } + + @Override + public byte[] getPLTStaticEntryCode(StubInformation stub) { + // The main dispatch instruction + // jmpq *0x00000000(%rip) + jmp(new AMD64Address(rip, 0)); + stub.setDispatchJumpOffset(position()); + + // C2I stub used to call interpreter. + // mov 0x00000000(%rip),%rbx Loading Method* + movq(rbx, new AMD64Address(rip, 0)); + stub.setMovOffset(position()); + + // jmpq *0x00000000(%rip) [c2i addr] + jmp(new AMD64Address(rip, 0)); + stub.setC2IJumpOffset(position()); + + // Call to VM runtime to resolve the call. + // jmpq *0x00000000(%rip) + stub.setResolveJumpStart(position()); + jmp(new AMD64Address(rip, 0)); + stub.setResolveJumpOffset(position()); + currentEndOfInstruction = position(); + + // Align to 8 bytes + align(8); + stub.setSize(position()); + + return close(true); + } + + @Override + public byte[] getPLTVirtualEntryCode(StubInformation stub) { + // Klass loading instruction + // mov 0x00000000(%rip),%rax + movq(rax, new AMD64Address(rip, 0)); + stub.setMovOffset(position()); + + // The main dispatch instruction + // jmpq *0x00000000(%rip) + jmp(new AMD64Address(rip, 0)); + stub.setDispatchJumpOffset(position()); + + // Call to VM runtime to resolve the call. + // jmpq *0x00000000(%rip) + stub.setResolveJumpStart(position()); + jmp(new AMD64Address(rip, 0)); + stub.setResolveJumpOffset(position()); + currentEndOfInstruction = position(); + + // Align to 8 bytes + align(8); + stub.setSize(position()); + + return close(true); + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java new file mode 100644 index 00000000000..9c084636c2b --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java @@ -0,0 +1,565 @@ +/* + * 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.amd64; + +import jdk.tools.jaotc.InstructionDecoder; + +import jdk.vm.ci.code.TargetDescription; + +public final class AMD64InstructionDecoder extends InstructionDecoder { + + private boolean targetIs64Bit; + private int currentEndOfInstruction; + + private static class Prefix { + + // segment overrides + public static final int CSSegment = 0x2e; + public static final int SSSegment = 0x36; + public static final int DSSegment = 0x3e; + public static final int ESSegment = 0x26; + public static final int FSSegment = 0x64; + public static final int GSSegment = 0x65; + public static final int REX = 0x40; + public static final int REXB = 0x41; + public static final int REXX = 0x42; + public static final int REXXB = 0x43; + public static final int REXR = 0x44; + public static final int REXRB = 0x45; + public static final int REXRX = 0x46; + public static final int REXRXB = 0x47; + public static final int REXW = 0x48; + public static final int REXWB = 0x49; + public static final int REXWX = 0x4A; + public static final int REXWXB = 0x4B; + public static final int REXWR = 0x4C; + public static final int REXWRB = 0x4D; + public static final int REXWRX = 0x4E; + public static final int REXWRXB = 0x4F; + public static final int VEX_3BYTES = 0xC4; + public static final int VEX_2BYTES = 0xC5; + } + + public static class VexPrefix { + public static final int VEX_R = 0x80; + public static final int VEX_W = 0x80; + } + + public static class VexOpcode { + public static final int VEX_OPCODE_NONE = 0x0; + public static final int VEX_OPCODE_0F = 0x1; + public static final int VEX_OPCODE_0F_38 = 0x2; + public static final int VEX_OPCODE_0F_3A = 0x3; + public static final int VEX_OPCODE_MASK = 0x1F; + } + + public AMD64InstructionDecoder(TargetDescription target) { + this.targetIs64Bit = target.wordSize == 8; + } + + @Override + public int currentEndOfInstruction() { + return currentEndOfInstruction; + } + + @Override + @SuppressWarnings("fallthrough") + public void decodePosition(final byte[] code, int pcOffset) { + assert pcOffset >= 0 && pcOffset < code.length; + + // Decode the given instruction, and return the Pointer of + // an embedded 32-bit operand word. + + // If "which" is WhichOperand.disp32operand, selects the displacement portion + // of an effective Pointer specifier. + // If "which" is imm64Operand, selects the trailing immediate constant. + // If "which" is WhichOperand.call32operand, selects the displacement of a call or jump. + // Caller is responsible for ensuring that there is such an operand, + // and that it is 32/64 bits wide. + + // If "which" is endPcOperand, find the end of the instruction. + + int ip = pcOffset; + boolean is64bit = false; + + boolean hasDisp32 = false; + int tailSize = 0; // other random bytes (#32, #16, etc.) at end of insn + + boolean againAfterPrefix = true; + + while (againAfterPrefix) { + againAfterPrefix = false; + switch (0xFF & code[ip++]) { + + // These convenience macros generate groups of "case" labels for the switch. + + case Prefix.CSSegment: + case Prefix.SSSegment: + case Prefix.DSSegment: + case Prefix.ESSegment: + case Prefix.FSSegment: + case Prefix.GSSegment: + // Seems dubious + assert !targetIs64Bit : "shouldn't have that prefix"; + assert ip == pcOffset + 1 : "only one prefix allowed"; + againAfterPrefix = true; + break; + + case 0x67: + case Prefix.REX: + case Prefix.REXB: + case Prefix.REXX: + case Prefix.REXXB: + case Prefix.REXR: + case Prefix.REXRB: + case Prefix.REXRX: + case Prefix.REXRXB: + assert targetIs64Bit : "64bit prefixes"; + againAfterPrefix = true; + break; + + case Prefix.REXW: + case Prefix.REXWB: + case Prefix.REXWX: + case Prefix.REXWXB: + case Prefix.REXWR: + case Prefix.REXWRB: + case Prefix.REXWRX: + case Prefix.REXWRXB: + assert targetIs64Bit : "64bit prefixes"; + is64bit = true; + againAfterPrefix = true; + break; + + case 0xFF: // pushq a; decl a; incl a; call a; jmp a + case 0x88: // movb a, r + case 0x89: // movl a, r + case 0x8A: // movb r, a + case 0x8B: // movl r, a + case 0x8F: // popl a + hasDisp32 = true; + break; + + case 0x68: // pushq #32 + currentEndOfInstruction = ip + 4; + return; // not produced by emitOperand + + case 0x66: // movw ... (size prefix) + boolean againAfterSizePrefix2 = true; + while (againAfterSizePrefix2) { + againAfterSizePrefix2 = false; + switch (0xFF & code[ip++]) { + case Prefix.REX: + case Prefix.REXB: + case Prefix.REXX: + case Prefix.REXXB: + case Prefix.REXR: + case Prefix.REXRB: + case Prefix.REXRX: + case Prefix.REXRXB: + case Prefix.REXW: + case Prefix.REXWB: + case Prefix.REXWX: + case Prefix.REXWXB: + case Prefix.REXWR: + case Prefix.REXWRB: + case Prefix.REXWRX: + case Prefix.REXWRXB: + assert targetIs64Bit : "64bit prefix found"; + againAfterSizePrefix2 = true; + break; + case 0x8B: // movw r, a + case 0x89: // movw a, r + hasDisp32 = true; + break; + case 0xC7: // movw a, #16 + hasDisp32 = true; + tailSize = 2; // the imm16 + break; + case 0x0F: // several SSE/SSE2 variants + ip--; // reparse the 0x0F + againAfterPrefix = true; + break; + default: + throw new InternalError("should not reach here"); + } + } + break; + + case 0xB8: // movl/q r, #32/#64(oop?) + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + currentEndOfInstruction = ip + (is64bit ? 8 : 4); + return; + + case 0x69: // imul r, a, #32 + case 0xC7: // movl a, #32(oop?) + tailSize = 4; + hasDisp32 = true; // has both kinds of operands! + break; + + case 0x0F: // movx..., etc. + switch (0xFF & code[ip++]) { + case 0x3A: // pcmpestri + ip++; // skip opcode + tailSize = 1; + hasDisp32 = true; // has both kinds of operands! + break; + + case 0x38: // ptest, pmovzxbw + ip++; // skip opcode + hasDisp32 = true; // has both kinds of operands! + break; + + case 0x70: // pshufd r, r/a, #8 + hasDisp32 = true; // has both kinds of operands! + tailSize = 1; + break; + + case 0x73: // psrldq r, #8 + tailSize = 1; + break; + + case 0x12: // movlps + case 0x28: // movaps + case 0x2E: // ucomiss + case 0x2F: // comiss + case 0x54: // andps + case 0x55: // andnps + case 0x56: // orps + case 0x57: // xorps + case 0x58: // addpd + case 0x59: // mulpd + case 0x6E: // movd + case 0x7E: // movd + case 0xAE: // ldmxcsr, stmxcsr, fxrstor, fxsave, clflush + case 0xFE: // paddd + // 64bit side says it these have both operands but that doesn't + // appear to be true + hasDisp32 = true; + break; + + case 0xAD: // shrd r, a, %cl + case 0xAF: // imul r, a + case 0xBE: // movsbl r, a (movsxb) + case 0xBF: // movswl r, a (movsxw) + case 0xB6: // movzbl r, a (movzxb) + case 0xB7: // movzwl r, a (movzxw) + case 0x40: // cmovl cc, r, a + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0xB0: // cmpxchgb + case 0xB1: // cmpxchg + case 0xC1: // xaddl + case 0xC7: // cmpxchg8 + case 0x90: // setcc a + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + hasDisp32 = true; + // fall out of the switch to decode the Pointer + break; + + case 0xC4: // pinsrw r, a, #8 + hasDisp32 = true; + tailSize = 1; // the imm8 + break; + + case 0xC5: // pextrw r, r, #8 + tailSize = 1; // the imm8 + break; + + case 0xAC: // shrd r, a, #8 + hasDisp32 = true; + tailSize = 1; // the imm8 + break; + + case 0x80: // jcc rdisp32 + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + currentEndOfInstruction = ip + 4; + return; + default: + throw new InternalError("should not reach here"); + } + break; + + case 0x81: // addl a, #32; addl r, #32 + // also: orl, adcl, sbbl, andl, subl, xorl, cmpl + // on 32bit in the case of cmpl, the imm might be an oop + tailSize = 4; + hasDisp32 = true; // has both kinds of operands! + break; + + case 0x83: // addl a, #8; addl r, #8 + // also: orl, adcl, sbbl, andl, subl, xorl, cmpl + hasDisp32 = true; // has both kinds of operands! + tailSize = 1; + break; + + case 0x9B: + switch (0xFF & code[ip++]) { + case 0xD9: // fnstcw a + hasDisp32 = true; + break; + default: + throw new InternalError("should not reach here"); + } + break; + + case 0x00: // addb a, r; addl a, r; addb r, a; addl r, a + case 0x01: + case 0x02: + case 0x03: + case 0x10: // adc... + case 0x11: + case 0x12: + case 0x13: + case 0x20: // and... + case 0x21: + case 0x22: + case 0x23: + case 0x30: // xor... + case 0x31: + case 0x32: + case 0x33: + case 0x08: // or... + case 0x09: + case 0x0a: + case 0x0b: + case 0x18: // sbb... + case 0x19: + case 0x1a: + case 0x1b: + case 0x28: // sub... + case 0x29: + case 0x2a: + case 0x2b: + case 0xF7: // mull a + case 0x8D: // lea r, a + case 0x87: // xchg r, a + case 0x38: // cmp... + case 0x39: + case 0x3a: + case 0x3b: + case 0x85: // test r, a + hasDisp32 = true; // has both kinds of operands! + break; + + case 0xC1: // sal a, #8; sar a, #8; shl a, #8; shr a, #8 + case 0xC6: // movb a, #8 + case 0x80: // cmpb a, #8 + case 0x6B: // imul r, a, #8 + hasDisp32 = true; // has both kinds of operands! + tailSize = 1; // the imm8 + break; + + case Prefix.VEX_3BYTES: + case Prefix.VEX_2BYTES: + assert ip == pcOffset + 1 : "no prefixes allowed"; + int vex_opcode; + // First byte + if ((code[pcOffset] & 0xFF) == Prefix.VEX_3BYTES) { + vex_opcode = VexOpcode.VEX_OPCODE_MASK & code[ip]; + ip++; // third byte + is64bit = ((VexPrefix.VEX_W & code[ip]) == VexPrefix.VEX_W); + } else { + vex_opcode = VexOpcode.VEX_OPCODE_0F; + } + ip++; // opcode + // To find the end of instruction (which == end_pc_operand). + switch (vex_opcode) { + case VexOpcode.VEX_OPCODE_0F: + switch (0xFF & code[ip]) { + case 0x70: // pshufd r, r/a, #8 + case 0x71: // ps[rl|ra|ll]w r, #8 + case 0x72: // ps[rl|ra|ll]d r, #8 + case 0x73: // ps[rl|ra|ll]q r, #8 + case 0xC2: // cmp[ps|pd|ss|sd] r, r, r/a, #8 + case 0xC4: // pinsrw r, r, r/a, #8 + case 0xC5: // pextrw r/a, r, #8 + case 0xC6: // shufp[s|d] r, r, r/a, #8 + tailSize = 1; // the imm8 + break; + default: + ; // no imm8 + } + break; + case VexOpcode.VEX_OPCODE_0F_3A: + tailSize = 1; + break; + default: + throw new InternalError("should not reach here"); + } + ip++; // skip opcode + hasDisp32 = true; + break; + + case 0xE8: // call rdisp32 + case 0xE9: // jmp rdisp32 + currentEndOfInstruction = ip + 4; + return; + + case 0xD1: // sal a, 1; sar a, 1; shl a, 1; shr a, 1 + case 0xD3: // sal a, %cl; sar a, %cl; shl a, %cl; shr a, %cl + case 0xD9: // fldS a; fstS a; fstpS a; fldcw a + case 0xDD: // fldD a; fstD a; fstpD a + case 0xDB: // fildS a; fistpS a; fldX a; fstpX a + case 0xDF: // fildD a; fistpD a + case 0xD8: // faddS a; fsubrS a; fmulS a; fdivrS a; fcompS a + case 0xDC: // faddD a; fsubrD a; fmulD a; fdivrD a; fcompD a + case 0xDE: // faddpD a; fsubrpD a; fmulpD a; fdivrpD a; fcomppD a + hasDisp32 = true; + break; + + case 0xF0: // Lock + againAfterPrefix = true; + break; + + case 0xF3: // For SSE + case 0xF2: // For SSE2 + switch (0xFF & code[ip++]) { + case Prefix.REX: + case Prefix.REXB: + case Prefix.REXX: + case Prefix.REXXB: + case Prefix.REXR: + case Prefix.REXRB: + case Prefix.REXRX: + case Prefix.REXRXB: + case Prefix.REXW: + case Prefix.REXWB: + case Prefix.REXWX: + case Prefix.REXWXB: + case Prefix.REXWR: + case Prefix.REXWRB: + case Prefix.REXWRX: + case Prefix.REXWRXB: + assert targetIs64Bit : "found 64bit prefix"; + ip++; + ip++; + break; + default: + ip++; + } + hasDisp32 = true; // has both kinds of operands! + break; + + default: + throw new InternalError("should not reach here"); + } + } + + assert hasDisp32 : "(tw) not sure if this holds: instruction has no disp32 field"; + + // parse the output of emitOperand + int op2 = 0xFF & code[ip++]; + int base = op2 & 0x07; + int op3 = -1; + int b100 = 4; + int b101 = 5; + if (base == b100 && (op2 >> 6) != 3) { + op3 = 0xFF & code[ip++]; + base = op3 & 0x07; // refetch the base + } + // now ip points at the disp (if any) + + switch (op2 >> 6) { + case 0: + // [00 reg 100][ss index base] + // [00 reg 100][00 100 esp] + // [00 reg base] + // [00 reg 100][ss index 101][disp32] + // [00 reg 101] [disp32] + if (base == b101) { + ip += 4; // skip the disp32 + } + break; + + case 1: + // [01 reg 100][ss index base][disp8] + // [01 reg 100][00 100 esp][disp8] + // [01 reg base] [disp8] + ip += 1; // skip the disp8 + break; + + case 2: + // [10 reg 100][ss index base][disp32] + // [10 reg 100][00 100 esp][disp32] + // [10 reg base] [disp32] + ip += 4; // skip the disp32 + break; + + case 3: + // [11 reg base] (not a memory addressing mode) + break; + } + + currentEndOfInstruction = ip + tailSize; + } + +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java new file mode 100644 index 00000000000..c46b3bfd062 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java @@ -0,0 +1,332 @@ +/* + * 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.collect; + +import jdk.tools.jaotc.LogPrinter; +import jdk.tools.jaotc.Main; + +import java.io.File; +import java.io.IOException; +import java.net.*; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.*; + +import static java.nio.file.FileVisitResult.CONTINUE; + +public class ClassCollector { + private final Main.Options options; + private final LogPrinter log; + + public ClassCollector(Main.Options options, LogPrinter log) { + this.options = options; + this.log = log; + } + + /** + * Collect all class names passed by the user. + * + * @return array list of classes + */ + public Set> collectClassesToCompile() { + Set> classes = new HashSet<>(); + List filesToScan = new LinkedList<>(options.files); + + if (options.module != null) { + classes.addAll(scanModule(filesToScan)); + } + + classes.addAll(scanFiles(filesToScan)); + return classes; + } + + private Set> scanModule(List filesToScan) { + String module = options.module; + // Search module in standard JDK installation. + Path dir = getModuleDirectory(options.modulepath, module); + + if (Files.isDirectory(dir)) { + return loadFromModuleDirectory(dir); + } else { + findFilesToScan(filesToScan, module); + return new HashSet<>(); + } + } + + private Set> loadFromModuleDirectory(Path dir) { + log.printInfo("Scanning module: " + dir + " ..."); + log.printlnVerbose(" "); // Break line + + FileSystemFinder finder = new FileSystemFinder(dir, pathname -> entryIsClassFile(pathname.toString())); + Set> cls = loadWithClassLoader(() -> ClassLoader.getSystemClassLoader(), dir, finder); + log.printlnInfo(" " + cls.size() + " classes loaded."); + return cls; + } + + private void findFilesToScan(List filesToScan, String module) { + // Try to search regular directory, .jar or .class files + Path path = Paths.get(options.modulepath, module); + + if (Files.isDirectory(path)) { + filesToScan.add("."); + options.classpath = path.toString(); + } else if (path.endsWith(".jar") || path.endsWith(".class")) { + filesToScan.add(path.toString()); + } else { + path = Paths.get(options.modulepath, module + ".jar"); + if (Files.exists(path)) { + filesToScan.add(path.toString()); + } else { + path = Paths.get(options.modulepath, module + ".class"); + if (Files.exists(path)) { + filesToScan.add(path.toString()); + } else { + throw new InternalError("Expecting a .class, .jar or directory: " + path); + } + } + } + } + + private boolean entryIsClassFile(String entry) { + return entry.endsWith(".class") && !entry.endsWith("module-info.class"); + } + + private Set> scanFiles(List filesToScan) { + Set> classes = new HashSet<>(); + for (String fileName : filesToScan) { + Set> loaded = scanFile(fileName); + log.printlnInfo(" " + loaded.size() + " classes loaded."); + classes.addAll(loaded); + } + return classes; + } + + interface ClassLoaderFactory { + ClassLoader create() throws IOException; + } + + private Set> loadWithClassLoader(ClassLoaderFactory factory, Path root, FileSystemFinder finder) { + ClassLoader loader = null; + try { + loader = factory.create(); + return loadClassFiles(root, finder, loader); + } catch (IOException e) { + throw new InternalError(e); + } finally { + if (loader instanceof AutoCloseable) { + try { + ((AutoCloseable) loader).close(); + } catch (Exception e) { + throw new InternalError(e); + } + } + } + } + + private Set> scanFile(String fileName) { + log.printInfo("Scanning: " + fileName + " ..."); + log.printlnVerbose(" "); // Break line + + if (fileName.endsWith(".jar")) { + return loadFromJarFile(fileName); + } else if (fileName.endsWith(".class")) { + Set> classes = new HashSet<>(); + loadFromClassFile(fileName, classes); + return classes; + } else { + return scanClassPath(fileName); + } + } + + private Set> loadFromJarFile(String fileName) { + FileSystem fs = makeFileSystem(fileName); + FileSystemFinder finder = new FileSystemFinder(fs.getPath("/"), pathname -> entryIsClassFile(pathname.toString())); + return loadWithClassLoader(() -> URLClassLoader.newInstance(buildUrls(fileName)), fs.getPath("/"), finder); + } + + private void loadFromClassFile(String fileName, Set> classes) { + Class result; + File file = new File(options.classpath); + try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) { + result = loadClassFile(loader, fileName); + } catch (IOException e) { + throw new InternalError(e); + } + Class c = result; + addClass(classes, fileName, c); + } + + private Set> scanClassPath(String fileName) { + Path classPath = Paths.get(options.classpath); + if (!Files.exists(classPath)) { + throw new InternalError("Path does not exist: " + classPath); + } + if (!Files.isDirectory(classPath)) { + throw new InternalError("Path must be a directory: " + classPath); + } + + // Combine class path and file name and see what it is. + Path combinedPath = Paths.get(options.classpath + File.separator + fileName); + if (combinedPath.endsWith(".class")) { + throw new InternalError("unimplemented"); + } else if (Files.isDirectory(combinedPath)) { + return scanDirectory(classPath, combinedPath); + } else { + throw new InternalError("Expecting a .class, .jar or directory: " + fileName); + } + } + + private FileSystem makeFileSystem(String fileName) { + try { + return FileSystems.newFileSystem(makeJarFileURI(fileName), new HashMap<>()); + } catch (IOException e) { + throw new InternalError(e); + } + } + + private URI makeJarFileURI(String fileName) { + try { + return new URI("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/"); + } catch (URISyntaxException e) { + throw new InternalError(e); + } + } + + private PathMatcher combine(PathMatcher m1, PathMatcher m2) { + return path -> m1.matches(path) && m2.matches(path); + } + + private Set> scanDirectory(Path classPath, Path combinedPath) { + String dir = options.classpath; + + FileSystem fileSystem = FileSystems.getDefault(); + PathMatcher matcher = fileSystem.getPathMatcher("glob:" + "*.class"); + FileSystemFinder finder = new FileSystemFinder(combinedPath, + combine(matcher, pathname -> entryIsClassFile(pathname.toString()))); + + File file = new File(dir); + try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) { + return loadClassFiles(classPath, finder, loader); + } catch (IOException e) { + throw new InternalError(e); + } + } + + private Set> loadClassFiles(Path root, FileSystemFinder finder, ClassLoader loader) { + Set> classes = new HashSet<>(); + for (Path name : finder.done()) { + // Now relativize to the class path so we get the actual class names. + String entry = root.relativize(name).normalize().toString(); + Class c = loadClassFile(loader, entry); + addClass(classes, entry, c); + } + return classes; + } + + private void addClass(Set> classes, String name, Class c) { + if (c != null) { + classes.add(c); + log.printlnVerbose(" loaded " + name); + } + } + + private URL[] buildUrls(String fileName) throws MalformedURLException { + return new URL[]{ new URL("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/") }; + } + + private URL[] buildUrls(File file) throws MalformedURLException { + return new URL[] {file.toURI().toURL() }; + } + + private Path getModuleDirectory(String modulepath, String module) { + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + return fs.getPath(modulepath, module); + } + + /** + * Loads a class with the given file name from the specified {@link URLClassLoader}. + */ + private Class loadClassFile(final ClassLoader loader, final String fileName) { + int start = 0; + if (fileName.startsWith("/")) { + start = 1; + } + String className = fileName.substring(start, fileName.length() - ".class".length()); + className = className.replace('/', '.'); + try { + return loader.loadClass(className); + } catch (Throwable e) { + // If we are running in JCK mode we ignore all exceptions. + if (options.ignoreClassLoadingErrors) { + log.printError(className + ": " + e); + return null; + } + throw new InternalError(e); + } + } + + /** + * {@link FileVisitor} implementation to find class files recursively. + */ + private static class FileSystemFinder extends SimpleFileVisitor { + private final ArrayList fileNames = new ArrayList<>(); + private final PathMatcher filter; + + FileSystemFinder(Path combinedPath, PathMatcher filter) { + this.filter = filter; + try { + Files.walkFileTree(combinedPath, this); + } catch (IOException e) { + throw new InternalError(e); + } + } + + /** + * Compares the glob pattern against the file name. + */ + void find(Path file) { + Path name = file.getFileName(); + if (name != null && filter.matches(name)) { + fileNames.add(file); + } + } + + List done() { + return fileNames; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + find(file); + return CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + find(dir); + return CONTINUE; + } + + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java new file mode 100644 index 00000000000..f1166a28231 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java @@ -0,0 +1,191 @@ +/* + * 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.utils; + +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +public class NativeOrderOutputStream { + private final PatchableByteOutputStream os = new PatchableByteOutputStream(); + private final byte[] backingArray = new byte[8]; + private final ByteBuffer buffer; + private final List patches = new ArrayList<>(); + private int size; + + public NativeOrderOutputStream() { + buffer = ByteBuffer.wrap(backingArray); + buffer.order(ByteOrder.nativeOrder()); + } + + public static int alignUp(int value, int alignment) { + if (Integer.bitCount(alignment) != 1) { + throw new IllegalArgumentException("Must be a power of 2"); + } + + int aligned = (value + (alignment - 1)) & -alignment; + + if (aligned < value || (aligned & (alignment - 1)) != 0) { + throw new RuntimeException("Error aligning: " + value + " -> " + aligned); + } + return aligned; + } + + public NativeOrderOutputStream putLong(long value) { + fillLong(value); + os.write(backingArray, 0, 8); + size += 8; + return this; + } + + public NativeOrderOutputStream putInt(int value) { + fillInt(value); + os.write(backingArray, 0, 4); + size += 4; + return this; + } + + public NativeOrderOutputStream align(int alignment) { + int aligned = alignUp(position(), alignment); + + int diff = aligned - position(); + if (diff > 0) { + byte[] b = new byte[diff]; + os.write(b, 0, b.length); + size += diff; + } + + assert aligned == position(); + return this; + } + + public int position() { + return os.size(); + } + + private void fillInt(int value) { + buffer.putInt(0, value); + } + + private void fillLong(long value) { + buffer.putLong(0, value); + } + + private NativeOrderOutputStream putAt(byte[] data, int length, int position) { + os.writeAt(data, length, position); + return this; + } + + public NativeOrderOutputStream put(byte[] data) { + os.write(data, 0, data.length); + size += data.length; + return this; + } + + public byte[] array() { + checkPatches(); + byte[] bytes = os.toByteArray(); + assert size == bytes.length; + return bytes; + } + + private void checkPatches() { + for (Patchable patch : patches) { + if (!patch.patched()) { + throw new RuntimeException("Not all patches patched, missing at offset: " + patch); + } + } + } + + public PatchableInt patchableInt() { + int position = os.size(); + PatchableInt patchableInt = new PatchableInt(position); + putInt(0); + patches.add(patchableInt); + return patchableInt; + } + + public abstract class Patchable { + private final int position; + private boolean patched = false; + + Patchable(int position) { + this.position = position; + } + + protected boolean patched() { + return patched; + } + + protected void patch(int length) { + putAt(backingArray, length, position); + patched = true; + } + + public int position() { + return position; + } + } + + public class PatchableInt extends Patchable { + private int value = 0; + + public PatchableInt(int position) { + super(position); + } + + public void set(int value) { + this.value = value; + fillInt(value); + patch(4); + } + + public int value() { + return value; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("PatchableInt{"); + sb.append("position=").append(super.position()).append(", "); + sb.append("patched=").append(patched()).append(", "); + sb.append("value=").append(value); + sb.append('}'); + return sb.toString(); + } + } + + private static class PatchableByteOutputStream extends ByteArrayOutputStream { + + public void writeAt(byte[] data, int length, int position) { + long end = (long)position + (long)length; + if (buf.length < end) { + throw new IllegalArgumentException("Array not properly sized"); + } + System.arraycopy(data, 0, buf, position, length); + } + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/Timer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/Timer.java new file mode 100644 index 00000000000..627c4d3035e --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/Timer.java @@ -0,0 +1,44 @@ +/* + * 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.utils; + +import jdk.tools.jaotc.Main; + +public class Timer implements AutoCloseable { + + private final Main main; + private final long start; + + public Timer(Main main, String message) { + this.main = main; + start = System.currentTimeMillis(); + main.printInfo(message); + } + + public void close() { + final long end = System.currentTimeMillis(); + main.printlnInfo(" (" + (end - start) + " ms)"); + } + +} diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/WSDisposable.java b/hotspot/src/jdk.aot/share/classes/module-info.java similarity index 86% rename from jdk/src/java.httpclient/share/classes/java/net/http/WSDisposable.java rename to hotspot/src/jdk.aot/share/classes/module-info.java index 5ece033e5cb..3105d8b6bef 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/WSDisposable.java +++ b/hotspot/src/jdk.aot/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,9 +23,8 @@ * questions. */ -package java.net.http; - -interface WSDisposable { - - void dispose(); +module jdk.aot { + requires jdk.management; + requires jdk.vm.ci; + requires jdk.vm.compiler; } diff --git a/hotspot/src/jdk.aot/unix/native/libjelfshim/jdk_tools_jaotc_jnilibelf_JNILibELFAPI.c b/hotspot/src/jdk.aot/unix/native/libjelfshim/jdk_tools_jaotc_jnilibelf_JNILibELFAPI.c new file mode 100644 index 00000000000..d6d69cb439a --- /dev/null +++ b/hotspot/src/jdk.aot/unix/native/libjelfshim/jdk_tools_jaotc_jnilibelf_JNILibELFAPI.c @@ -0,0 +1,522 @@ +/* + * 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 "jdk_tools_jaotc_jnilibelf_JNILibELFAPI.h" + +// For file open and close +#include +#include +#include +#include +#include +#include + +#include + +// For libelf interfaces +#include +#include + +// Convenience macro to shut the compiler warnings +#ifdef UNUSED +#elif defined(__GNUC__) +# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) +#elif defined(__LCLINT__) +# define UNUSED(x) /*@unused@*/ x +#else +# define UNUSED(x) x +#endif + +/** + * libelfshim version + */ +#ifndef AOT_VERSION_STRING + #error AOT_VERSION_STRING must be defined +#endif + +JNIEXPORT jstring JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elfshim_1version +(JNIEnv* env, jclass UNUSED(c)) { + const char* ver = AOT_VERSION_STRING; + return (*env)->NewStringUTF(env, ver); +} + +JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1version +(JNIEnv* UNUSED(env), jclass UNUSED(c), jint v) { + return elf_version(v); +} + +/** + * Unbox the Pointer object the encapsulated native address. + */ + +static jlong getNativeAddress(JNIEnv* env, jobject ptrObj) { + jclass ptrClass; + jfieldID fidNumber; + jlong nativeAddress = -1; + assert (ptrObj != NULL); + // Get a reference to ptr object's class + ptrClass = (*env)->GetObjectClass(env, ptrObj); + + // Get the Field ID of the instance variables "address" + fidNumber = (*env)->GetFieldID(env, ptrClass, "address", "J"); + if (fidNumber != NULL) { + // Get the long given the Field ID + nativeAddress = (*env)->GetLongField(env, ptrObj, fidNumber); + } + // fprintf(stderr, "Native address : %lx\n", nativeAddress); + return nativeAddress; +} + +/** + * Box the nativeAddress as a Pointer object. + */ +static jobject makePointerObject(JNIEnv* env, jlong nativeAddr) { + jclass ptrClass = (*env)->FindClass(env, "jdk/tools/jaotc/jnilibelf/Pointer"); + // Call back constructor to allocate a Pointer object, with an int argument + jmethodID constructorId = (*env)->GetMethodID(env, ptrClass, "", "(J)V"); + jobject retObj = (*env)->NewObject(env, ptrClass, constructorId, nativeAddr); + return retObj; +} + +JNIEXPORT jobject JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1begin +(JNIEnv* env, jclass UNUSED(class), jint filedes, jint cmd, jobject ptrObj) { + + Elf* elfPtr = NULL; + jlong addr = getNativeAddress(env, ptrObj); + + if (addr != -1) { + // Call libelf function + if ((elfPtr = elf_begin(filedes, cmd, (Elf *) addr)) == NULL) { + errx(EX_SOFTWARE, "elf_begin() failed: %s.", elf_errmsg(-1)); + } + } else { + fprintf(stderr, "Failed to get native address to call elf_begin()\n"); + } + + return makePointerObject(env, (jlong) elfPtr); +} + +JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1end +(JNIEnv* env, jclass UNUSED(class), jobject ptrObj) { + + jlong addr = getNativeAddress(env, ptrObj); + + if (addr != -1) { + // Call libelf function + return elf_end((Elf *) addr); + } else { + fprintf(stderr, "Failed to get native address to call elf_end()\n"); + return -1; + } +} + +JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1kind +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj) { + jlong addr = getNativeAddress(env, ptrObj); + + if (addr != -1) { + // Call libelf function + return elf_kind((Elf *) addr); + } else { + fprintf(stderr, "Failed to get native address to call elf_kind()\n"); + return -1; + } +} +JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1flagphdr +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint cmd, jint flags) { + + jlong addr = getNativeAddress(env, ptrObj); + unsigned int retVal = 0; + + if (addr != -1) { + // Call libelf function + if ((retVal = elf_flagphdr((Elf *) addr, cmd, flags)) == 0) { + errx(EX_SOFTWARE, "elf_flagphdr() failed: %s.", elf_errmsg(-1)); + } + } else { + fprintf(stderr, "Failed to get native address to call elf_flagphdr()\n"); + } + return retVal; +} + +JNIEXPORT jobject JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1newscn +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj) { + + Elf_Scn* elfSecPtr = NULL; + jlong addr = getNativeAddress(env, ptrObj); + + if (addr != -1) { + // Call libelf function + if ((elfSecPtr = elf_newscn((Elf *) addr)) == NULL) { + errx(EX_SOFTWARE, "elf_newscn() failed: %s.", elf_errmsg(-1)); + } + } else { + fprintf(stderr, "Failed to get native address to call elf_newscn()\n"); + } + + return makePointerObject(env, (jlong) elfSecPtr); +} + +JNIEXPORT jobject JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1newdata +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj) { + + Elf_Data* elfDataPtr = NULL; + jlong addr = getNativeAddress(env, ptrObj); + + if (addr != -1) { + // Call libelf function + if ((elfDataPtr = elf_newdata((Elf_Scn *) addr)) == NULL) { + errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1)); + } + } else { + fprintf(stderr, "Failed to get native address to call elf_newdata()\n"); + } + return makePointerObject(env, (jlong) elfDataPtr); +} + +JNIEXPORT jobject JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf64_1getshdr +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj) { + + Elf64_Shdr* elf64ShdrPtr = NULL; + jlong addr = getNativeAddress(env, ptrObj); + + if (addr != -1) { + // Call libelf function + if ((elf64ShdrPtr = elf64_getshdr((Elf_Scn *) addr)) == NULL) { + errx(EX_SOFTWARE, "elf64_getshdr() failed: %s.", elf_errmsg(-1)); + } + } else { + fprintf(stderr, "Failed to get native address to call elf_getshdr()\n"); + } + return makePointerObject(env, (jlong) elf64ShdrPtr); +} + +JNIEXPORT jlong JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1update +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint cmd) { + + off_t size = -1; + jlong addr = getNativeAddress(env, ptrObj); + + if (addr != -1) { + // Call libelf function + if ((size = elf_update((Elf*) addr, cmd)) == -1) { + errx(EX_SOFTWARE, "elf_update() failed: %s size (%d) cmd (%d).", elf_errmsg(-1), (int)size, cmd); + } + } else { + fprintf(stderr, "Failed to get native address to call elf_update()\n"); + } + return size; +} + +JNIEXPORT jstring JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1errmsg +(JNIEnv* env, jclass UNUSED(c), jint errno) { + + const char * retPtr = NULL; + // Call libelf function + if ((retPtr = elf_errmsg(errno)) == NULL) { + errx(EX_SOFTWARE, "elf_errmsg() failed: %s.", elf_errmsg(-1)); + } + return (*env)->NewStringUTF(env, retPtr); +} + +JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1ndxscn +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj) { + jint secnum = SHN_UNDEF; + jlong addr = getNativeAddress(env, ptrObj); + if (addr != -1) { + // Call libelf function + secnum = elf_ndxscn((Elf_Scn*) addr); + } else { + fprintf(stderr, "Failed to get native address to call elf_ndxscn()\n"); + } + return secnum; +} + +JNIEXPORT jobject JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_gelf_1newehdr +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint elfClass) { + unsigned long int retPtr = 0; + jlong addr = getNativeAddress(env, ptrObj); + if (addr != -1) { + // Call libelf function + if ((retPtr = gelf_newehdr((Elf*) addr, elfClass)) == 0) { + errx(EX_SOFTWARE, "gelf_newehdr() failed: %s.", elf_errmsg(-1)); + } + } else { + fprintf(stderr, "Failed to get native address to call elf_newehdr()\n"); + } + return makePointerObject(env, (jlong) retPtr); +} + +JNIEXPORT jobject JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_gelf_1newphdr +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint phnum) { + unsigned long int retPtr = 0; + jlong addr = getNativeAddress(env, ptrObj); + if (addr != -1) { + // Call libelf function + if ((retPtr = gelf_newphdr((Elf*) addr, phnum)) == 0) { + errx(EX_SOFTWARE, "gelf_newphdr() failed: %s.", elf_errmsg(-1)); + } + } else { + fprintf(stderr, "Failed to get native address to call elf_newphdr()\n"); + } + return makePointerObject(env, (jlong) retPtr); +} + + +/* File operations */ + +JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_open_1rw +(JNIEnv * env, jclass UNUSED(class), jstring jfileName) { + int flags = O_RDWR | O_CREAT | O_TRUNC; + int mode = 0666; + int retVal; + const char* cfileName = (*env)->GetStringUTFChars(env, jfileName, NULL); + if (cfileName == NULL) { + return -1; + } + retVal = open(cfileName, flags, mode); + if (retVal < 0) { + err(EX_NOINPUT, "open %s failed", cfileName); + } + (*env)->ReleaseStringUTFChars(env, jfileName, cfileName); + + return retVal; +} + +JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_open__Ljava_lang_String_2I +(JNIEnv * env, jclass UNUSED(class), jstring jfileName, jint flags) { + int retVal; + const char* cfileName = (*env)->GetStringUTFChars(env, jfileName, NULL); + if (cfileName == NULL) { + return -1; + } + retVal = open(cfileName, flags); + if (retVal < 0) { + err(EX_NOINPUT, "open %s failed", cfileName); + } + (*env)->ReleaseStringUTFChars(env, jfileName, cfileName); + + return retVal; +} + +JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_open__Ljava_lang_String_2II +(JNIEnv * env, jclass UNUSED(class), jstring jfileName, jint flags, jint mode) { + int retVal; + const char* cfileName = (*env)->GetStringUTFChars(env, jfileName, NULL); + if (cfileName == NULL) { + return -1; + } + retVal = open(cfileName, flags, mode); + if (retVal < 0) { + err(EX_NOINPUT, "open %s failed", cfileName); + } + (*env)->ReleaseStringUTFChars(env, jfileName, cfileName); + + return retVal; +} + + +JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_close +(JNIEnv* UNUSED(env), jclass UNUSED(class), jint fd) { + return close(fd); +} + +/** + * Miscellaneous ELF data structure peek-poke functions in + * shim_functions.c. No corresponding .h file exists yet. + * So each function needs to be declared as extern + */ + +extern int size_of_Sym(int elfclass); +extern int size_of_Rel(int elfclass); +extern int size_of_Rela(int elfclass); + +extern void ehdr_set_data_encoding(void * ehdr, int val); +extern void set_Ehdr_e_machine(int elfclass, void * structPtr, int val); +extern void set_Ehdr_e_type(int elfclass, void * structPtr, int val); +extern void set_Ehdr_e_version(int elfclass, void * structPtr, int val); +extern void set_Ehdr_e_shstrndx(int elfclass, void * structPtr, int val); + +extern void phdr_set_type_self(int elfclass, void * ehdr, void * phdr); +extern void phdr_set_type_self(int elfclass, void * ehdr, void * phdr); + +extern void set_Shdr_sh_name(int elfclass, void* structPtr, int val); +extern void set_Shdr_sh_type(int elfclass, void* structPtr, int val); +extern void set_Shdr_sh_flags(int elfclass, void* structPtr, int val); +extern void set_Shdr_sh_entsize(int elfclass, void* structPtr, int val); +extern void set_Shdr_sh_link(int elfclass, void* structPtr, int val); +extern void set_Shdr_sh_info(int elfclass, void* structPtr, int val); + +extern void set_Data_d_align(void* structPtr, int val); +extern void set_Data_d_off(void* structPtr, int val); +extern void set_Data_d_buf(void* structPtr, void* val); +extern void set_Data_d_type(void* structPtr, int val); +extern void set_Data_d_size(void* structPtr, int val); +extern void set_Data_d_version(void* structPtr, int val); + +extern void* create_sym_entry(int elfclass, int index, int type, int bind, + int shndx, int size, int value); +extern void * create_reloc_entry(int elfclass, int roffset, int symtabIdx, + int relocType, int raddend, int reloca); + +JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_size_1of_1Sym +(JNIEnv* UNUSED(env), jclass UNUSED(c), jint elfClass) { + return size_of_Sym(elfClass); +} + +JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_size_1of_1Rela +(JNIEnv* UNUSED(env), jclass UNUSED(c), jint elfClass) { + return size_of_Rela(elfClass); +} + +JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_size_1of_1Rel +(JNIEnv* UNUSED(env), jclass UNUSED(c), jint elfClass) { + return size_of_Rel(elfClass); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_ehdr_1set_1data_1encoding +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint val) { + void* ehdr = (void*) getNativeAddress(env, ptrObj); + ehdr_set_data_encoding(ehdr, val); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Ehdr_1e_1machine +(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) { + void* ehdr = (void*) getNativeAddress(env, ptrObj); + set_Ehdr_e_machine(elfClass, ehdr, val); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Ehdr_1e_1type +(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) { + void* ehdr = (void*) getNativeAddress(env, ptrObj); + set_Ehdr_e_type(elfClass, ehdr, val); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Ehdr_1e_1version +(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) { + void* ehdr = (void*) getNativeAddress(env, ptrObj); + set_Ehdr_e_version(elfClass, ehdr, val); +} +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Ehdr_1e_1shstrndx +(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) { + void* shdr = (void*) getNativeAddress(env, ptrObj); + set_Ehdr_e_shstrndx(elfClass, shdr, val); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_phdr_1set_1type_1self +(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ehdrPtr, jobject phdrPtr) { + void* ehdr = (void*) getNativeAddress(env, ehdrPtr); + void* phdr = (void*) getNativeAddress(env, phdrPtr); + phdr_set_type_self(elfClass, ehdr, phdr); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Shdr_1sh_1name +(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) { + void* shdr = (void*) getNativeAddress(env, ptrObj); + set_Shdr_sh_name(elfClass, shdr, val); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Shdr_1sh_1type +(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) { + void* shdr = (void*) getNativeAddress(env, ptrObj); + set_Shdr_sh_type(elfClass, shdr, val); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Shdr_1sh_1flags +(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) { + void* shdr = (void*) getNativeAddress(env, ptrObj); + set_Shdr_sh_flags(elfClass, shdr, val); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Shdr_1sh_1entsize +(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) { + void* shdr = (void*) getNativeAddress(env, ptrObj); + set_Shdr_sh_entsize(elfClass, shdr, val); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Shdr_1sh_1info +(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) { + void* shdr = (void*) getNativeAddress(env, ptrObj); + set_Shdr_sh_info(elfClass, shdr, val); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Shdr_1sh_1link +(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) { + void* shdr = (void*) getNativeAddress(env, ptrObj); + set_Shdr_sh_link(elfClass, shdr, val); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Data_1d_1align +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint val) { + void* dptr = (void*) getNativeAddress(env, ptrObj); + set_Data_d_align(dptr, val); +} + + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Data_1d_1off +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint val) { + void* dptr = (void*) getNativeAddress(env, ptrObj); + set_Data_d_off(dptr, val); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Data_1d_1buf +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jobject bufPtr) { + void* dptr = (void*) getNativeAddress(env, ptrObj); + void* bptr = (void*) getNativeAddress(env, bufPtr); + set_Data_d_buf(dptr, bptr); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Data_1d_1type +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint val) { + void* dptr = (void*) getNativeAddress(env, ptrObj); + set_Data_d_type(dptr, val); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Data_1d_1size +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint val) { + void* dptr = (void*) getNativeAddress(env, ptrObj); + set_Data_d_size(dptr, val); +} + +JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Data_1d_1version +(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint val) { + void* dptr = (void*) getNativeAddress(env, ptrObj); + set_Data_d_version(dptr, val); +} + +JNIEXPORT jlong JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_create_1sym_1entry +(JNIEnv* UNUSED(env), jclass UNUSED(c), jint elfClass, jint index, jint type, + jint bind, jint shndx, jint size, jint value) { + void * retVal = create_sym_entry(elfClass, index, type, bind, + shndx, size, value); + return (jlong)retVal; +} + +JNIEXPORT jlong JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_create_1reloc_1entry +(JNIEnv* UNUSED(env), jclass UNUSED(c), jint elfClass, jint roffset, + jint symTabIdx, jint relocType, jint raddend, jint reloca) { + void * retVal = create_reloc_entry(elfClass, roffset, symTabIdx, + relocType, raddend, reloca); + return (jlong)retVal; +} + diff --git a/hotspot/src/jdk.aot/unix/native/libjelfshim/shim_functions.c b/hotspot/src/jdk.aot/unix/native/libjelfshim/shim_functions.c new file mode 100644 index 00000000000..e405b0d26c0 --- /dev/null +++ b/hotspot/src/jdk.aot/unix/native/libjelfshim/shim_functions.c @@ -0,0 +1,226 @@ +/* + * 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 +#include +#include + +/** + * TODO: This is an intial and crude attempt to access structure + * fields of some ELF structrures. Need to figure out a way to access the + * given field of a given structure instead of writing one shim function + * per access of each of the structure field. + **/ + +#define STRINGIFYHELPER(x) #x +#define STRINGIFY(x) STRINGIFYHELPER(x) +#define FUNC_NAME(S, F) set_ ## S ## _ ## F +#define CAST_STRUCT(S, F) ((Elf_ ## S *) structPtr) +#define CAST_STRUCT32(S, F) ((Elf32_ ## S *) structPtr) +#define CAST_STRUCT64(S, F) ((Elf64_ ## S *) structPtr) +#define ACCESS_FIELD(S, F) CAST_STRUCT(S, F)-> F +#define ACCESS_FIELD32(S, F) CAST_STRUCT32(S, F)-> F +#define ACCESS_FIELD64(S, F) CAST_STRUCT64(S, F)-> F + +/* + Example: + SET_TYPE_BASED_FIELD(Ehdr, e_machine, int) + expands to + set_Ehdr_e_machine(int elfclass, void * strPtr, int val) { +} +*/ + +#define SET_TYPE_BASED_FIELD(S, F, T) \ + void FUNC_NAME(S, F)(int elfclass, void * structPtr, T val) { \ + if (elfclass == ELFCLASS32) { \ + ACCESS_FIELD32(S, F) = val; \ + } else if (elfclass == ELFCLASS64) { \ + ACCESS_FIELD64(S, F) = val; \ + } else { \ + printf("%s: Unknown ELF Class %d provided\n", STRINGIFY(FUNC_NAME(S, F)), elfclass); \ + } \ + return; \ +} + +/* + Example: + SET_FIELD(Ehdr, e_machine, int) + expands to + set_Ehdr_e_machine(void * strPtr, int val) { +} +*/ + +#define SET_FIELD(S, F, T) \ + void FUNC_NAME(S, F)(void * structPtr, T val) { \ + ACCESS_FIELD(S, F) = val; \ + return; \ +} + +int size_of_Sym(int elfclass) { + if (elfclass == ELFCLASS32) { + return sizeof(Elf32_Sym); + } else if (elfclass == ELFCLASS64) { + return sizeof(Elf64_Sym); + } else { + printf("Unknown ELF Class %d provided\n", elfclass); + } + return -1; +} + +int size_of_Rela(int elfclass) { + if (elfclass == ELFCLASS32) { + return sizeof(Elf32_Rela); + } else if (elfclass == ELFCLASS64) { + return sizeof(Elf64_Rela); + } else { + printf("Unknown ELF Class %d provided\n", elfclass); + } + return -1; +} + +int size_of_Rel(int elfclass) { + if (elfclass == ELFCLASS32) { + return sizeof(Elf32_Rel); + } else if (elfclass == ELFCLASS64) { + return sizeof(Elf64_Rel); + } else { + printf("Unknown ELF Class %d provided\n", elfclass); + } + return -1; +} + +/* ELF Header field access */ + +void ehdr_set_data_encoding(void * ehdr, int val) { + ((Elf32_Ehdr *) ehdr)->e_ident[EI_DATA] = val; + return; +} + +SET_TYPE_BASED_FIELD(Ehdr, e_machine, int) +SET_TYPE_BASED_FIELD(Ehdr, e_type, int) +SET_TYPE_BASED_FIELD(Ehdr, e_version, int) +SET_TYPE_BASED_FIELD(Ehdr, e_shstrndx, int) + +/* Data descriptor field access */ +SET_FIELD(Data, d_align, int) +SET_FIELD(Data, d_off, int) +SET_FIELD(Data, d_buf, void*) +SET_FIELD(Data, d_type, int) +SET_FIELD(Data, d_size, int) +SET_FIELD(Data, d_version, int) + +/* Section Header Access functions */ +SET_TYPE_BASED_FIELD(Shdr, sh_name, int) +SET_TYPE_BASED_FIELD(Shdr, sh_type, int) +SET_TYPE_BASED_FIELD(Shdr, sh_flags, int) +SET_TYPE_BASED_FIELD(Shdr, sh_entsize, int) +SET_TYPE_BASED_FIELD(Shdr, sh_link, int) +SET_TYPE_BASED_FIELD(Shdr, sh_info, int) + +/* Set the Program Header to be of PH_PHDR type and initialize other + related fields of the program header. +*/ +void phdr_set_type_self(int elfclass, void * ehdr, void * phdr) { + if (elfclass == ELFCLASS32) { + Elf32_Ehdr * ehdr32 = (Elf32_Ehdr *) ehdr; + Elf32_Phdr * phdr32 = (Elf32_Phdr *) phdr; + phdr32->p_type = PT_PHDR; + phdr32->p_offset = ehdr32->e_phoff; + phdr32->p_filesz = elf32_fsize(ELF_T_PHDR, 1, EV_CURRENT); + } else if (elfclass == ELFCLASS64) { + Elf64_Ehdr * ehdr64 = (Elf64_Ehdr *) ehdr; + Elf64_Phdr * phdr64 = (Elf64_Phdr *) phdr; + phdr64->p_type = PT_PHDR; + phdr64->p_offset = ehdr64->e_phoff; + phdr64->p_filesz = elf64_fsize(ELF_T_PHDR, 1, EV_CURRENT); + } else { + printf("phdr_set_type_self: Unknown ELF Class %d provided\n", elfclass); + } + return; +} + +/* + Create symbol table entry with given type and binding +*/ +void * create_sym_entry(int elfclass, int index, int type, int bind, + int shndx, int size, int value) { + void * symentry = NULL; + if (elfclass == ELFCLASS32) { + Elf32_Sym * sym32 = (Elf32_Sym *) malloc(sizeof(Elf32_Sym)); + sym32->st_name = index; + sym32->st_value = value; + sym32->st_size = size; + sym32->st_info = ELF32_ST_INFO(bind, type); + sym32->st_other = 0; // TODO: Add an argument to get this value ?? + sym32->st_shndx = shndx; + symentry = sym32; + } else if (elfclass == ELFCLASS64) { + Elf64_Sym * sym64 = (Elf64_Sym *) malloc(sizeof(Elf64_Sym)); + sym64->st_name = index; + sym64->st_value = value; + sym64->st_size = size; + sym64->st_info = ELF64_ST_INFO(bind, type); + sym64->st_other = 0; // TODO: Add an argument to get this value ?? + sym64->st_shndx = shndx; + symentry = sym64; + } else { + printf("create_sym_entry: Unknown ELF Class %d provided\n", elfclass); + } + return (void *) symentry; +} + +// Create a reloc (or reloca entry if argument reloca is non-zero) +void * create_reloc_entry(int elfclass, int roffset, int symtabIdx, + int relocType, int raddend, int reloca) { + void * relocentry = NULL; + if (elfclass == ELFCLASS32) { + if (reloca) { + Elf32_Rela * rela32 = (Elf32_Rela *) malloc(sizeof(Elf32_Rela)); + rela32->r_offset = roffset; + rela32->r_info = ELF32_R_INFO(symtabIdx, relocType); + rela32->r_addend = raddend; + relocentry = rela32; + } else { + Elf32_Rel * rel32 = (Elf32_Rel *) malloc(sizeof(Elf32_Rel)); + rel32->r_offset = roffset; + rel32->r_info = ELF32_R_INFO(symtabIdx, relocType); + relocentry = rel32; + } + } else if (elfclass == ELFCLASS64) { + if (reloca) { + Elf64_Rela * rela64 = (Elf64_Rela *) malloc(sizeof(Elf64_Rela)); + rela64->r_offset = roffset; + rela64->r_info = ELF64_R_INFO(symtabIdx, relocType); + rela64->r_addend = raddend; + relocentry = rela64; + } else { + Elf64_Rel * rel64 = (Elf64_Rel *) malloc(sizeof(Elf64_Rel)); + rel64->r_offset = roffset; + rel64->r_info = ELF64_R_INFO(symtabIdx, relocType); + relocentry = rel64; + } + } else { + printf("create_reloc_entry: Unknown ELF Class %d provided\n", elfclass); + } + return (void *) relocentry; +} diff --git a/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c index 1c96cf3e370..45299fd8802 100644 --- a/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c +++ b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c @@ -387,8 +387,8 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t if (shdr->sh_type == sym_section) { ELF_SYM *syms; - int j, n, rslt; - size_t size; + int rslt; + size_t size, n, j, htab_sz; // FIXME: there could be multiple data buffers associated with the // same ELF section. Here we can handle only one buffer. See man page @@ -407,6 +407,15 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t // create hash table, we use hcreate_r, hsearch_r and hdestroy_r to // manipulate the hash table. + + // NOTES section in the man page of hcreate_r says + // "Hash table implementations are usually more efficient when + // the table contains enough free space to minimize collisions. + // Typically, this means that nel should be at least 25% larger + // than the maximum number of elements that the caller expects + // to store in the table." + htab_sz = n*1.25; + symtab->hash_table = (struct hsearch_data*) calloc(1, sizeof(struct hsearch_data)); rslt = hcreate_r(n, symtab->hash_table); // guarantee(rslt, "unexpected failure: hcreate_r"); @@ -452,7 +461,6 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t symtab->symbols[j].offset = sym_value - baseaddr; item.key = sym_name; item.data = (void *)&(symtab->symbols[j]); - hsearch_r(item, ENTER, &ret, symtab->hash_table); } } diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java index 19eae4ef9de..4c4005428ce 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java @@ -102,4 +102,17 @@ public class Dictionary extends TwoOopHashtable { } return null; } + + public boolean contains(Klass c, Oop classLoader) { + long hash = computeHash(c.getName(), classLoader); + int index = hashToIndex(hash); + + for (DictionaryEntry entry = (DictionaryEntry) bucket(index); entry != null; + entry = (DictionaryEntry) entry.next()) { + if (entry.literalValue().equals(c.getAddress())) { + return true; + } + } + return false; + } } diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index db8a1c15ffc..742ec9a32e0 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @@ -29,6 +29,7 @@ import java.util.*; import sun.jvm.hotspot.classfile.ClassLoaderData; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.memory.*; +import sun.jvm.hotspot.memory.Dictionary; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.utilities.*; @@ -64,6 +65,21 @@ public class InstanceKlass extends Klass { private static int CLASS_STATE_FULLY_INITIALIZED; private static int CLASS_STATE_INITIALIZATION_ERROR; + // _misc_flags constants + private static int MISC_REWRITTEN; + private static int MISC_HAS_NONSTATIC_FIELDS; + private static int MISC_SHOULD_VERIFY_CLASS; + private static int MISC_IS_ANONYMOUS; + private static int MISC_IS_CONTENDED; + private static int MISC_HAS_NONSTATIC_CONCRETE_METHODS; + private static int MISC_DECLARES_NONSTATIC_CONCRETE_METHODS; + private static int MISC_HAS_BEEN_REDEFINED; + private static int MISC_HAS_PASSED_FINGERPRINT_CHECK; + private static int MISC_IS_SCRATCH_CLASS; + private static int MISC_IS_SHARED_BOOT_CLASS; + private static int MISC_IS_SHARED_PLATFORM_CLASS; + private static int MISC_IS_SHARED_APP_CLASS; + private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("InstanceKlass"); arrayKlasses = new MetadataField(type.getAddressField("_array_klasses"), 0); @@ -90,6 +106,7 @@ public class InstanceKlass extends Klass { breakpoints = type.getAddressField("_breakpoints"); } genericSignatureIndex = new CIntField(type.getCIntegerField("_generic_signature_index"), 0); + miscFlags = new CIntField(type.getCIntegerField("_misc_flags"), 0); majorVersion = new CIntField(type.getCIntegerField("_major_version"), 0); minorVersion = new CIntField(type.getCIntegerField("_minor_version"), 0); headerSize = type.getSize(); @@ -114,6 +131,19 @@ public class InstanceKlass extends Klass { CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("InstanceKlass::fully_initialized").intValue(); CLASS_STATE_INITIALIZATION_ERROR = db.lookupIntConstant("InstanceKlass::initialization_error").intValue(); + MISC_REWRITTEN = db.lookupIntConstant("InstanceKlass::_misc_rewritten").intValue(); + MISC_HAS_NONSTATIC_FIELDS = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_fields").intValue(); + MISC_SHOULD_VERIFY_CLASS = db.lookupIntConstant("InstanceKlass::_misc_should_verify_class").intValue(); + MISC_IS_ANONYMOUS = db.lookupIntConstant("InstanceKlass::_misc_is_anonymous").intValue(); + MISC_IS_CONTENDED = db.lookupIntConstant("InstanceKlass::_misc_is_contended").intValue(); + MISC_HAS_NONSTATIC_CONCRETE_METHODS = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_concrete_methods").intValue(); + MISC_DECLARES_NONSTATIC_CONCRETE_METHODS = db.lookupIntConstant("InstanceKlass::_misc_declares_nonstatic_concrete_methods").intValue(); + MISC_HAS_BEEN_REDEFINED = db.lookupIntConstant("InstanceKlass::_misc_has_been_redefined").intValue(); + MISC_HAS_PASSED_FINGERPRINT_CHECK = db.lookupIntConstant("InstanceKlass::_misc_has_passed_fingerprint_check").intValue(); + MISC_IS_SCRATCH_CLASS = db.lookupIntConstant("InstanceKlass::_misc_is_scratch_class").intValue(); + MISC_IS_SHARED_BOOT_CLASS = db.lookupIntConstant("InstanceKlass::_misc_is_shared_boot_class").intValue(); + MISC_IS_SHARED_PLATFORM_CLASS = db.lookupIntConstant("InstanceKlass::_misc_is_shared_platform_class").intValue(); + MISC_IS_SHARED_APP_CLASS = db.lookupIntConstant("InstanceKlass::_misc_is_shared_app_class").intValue(); } public InstanceKlass(Address addr) { @@ -149,6 +179,7 @@ public class InstanceKlass extends Klass { private static CIntField itableLen; private static AddressField breakpoints; private static CIntField genericSignatureIndex; + private static CIntField miscFlags; private static CIntField majorVersion; private static CIntField minorVersion; @@ -243,7 +274,7 @@ public class InstanceKlass extends Klass { return getSizeHelper() * VM.getVM().getAddressSize(); } - public long getSize() { + public long getSize() { // in number of bytes long wordLength = VM.getVM().getBytesPerWord(); long size = getHeaderSize() + (getVtableLen() + @@ -252,9 +283,59 @@ public class InstanceKlass extends Klass { if (isInterface()) { size += wordLength; } + if (isAnonymous()) { + size += wordLength; + } + if (hasStoredFingerprint()) { + size += 8; // uint64_t + } return alignSize(size); } + private int getMiscFlags() { + return (int) miscFlags.getValue(this); + } + + public boolean isAnonymous() { + return (getMiscFlags() & MISC_IS_ANONYMOUS) != 0; + } + + public static boolean shouldStoreFingerprint() { + VM vm = VM.getVM(); + if (vm.getCommandLineBooleanFlag("EnableJVMCI") && !vm.getCommandLineBooleanFlag("UseJVMCICompiler")) { + return true; + } + if (vm.getCommandLineBooleanFlag("DumpSharedSpaces")) { + return true; + } + return false; + } + + public boolean hasStoredFingerprint() { + return shouldStoreFingerprint() || isShared(); + } + + public boolean isShared() { + VM vm = VM.getVM(); + if (vm.isSharingEnabled()) { + // This is not the same implementation as the C++ function MetaspaceObj::is_shared() + // bool MetaspaceObj::is_shared() const { + // return MetaspaceShared::is_in_shared_space(this); + // } + // However, MetaspaceShared::is_in_shared_space is complicated and hard to emulate in + // Java code, so let's do this by looking up from the shared dictionary. Of course, + // this works for shared InstanceKlass only and does not work for other types of + // MetaspaceObj in the CDS shared archive. + Dictionary sharedDictionary = vm.getSystemDictionary().sharedDictionary(); + if (sharedDictionary != null) { + if (sharedDictionary.contains(this, null)) { + return true; + } + } + } + return false; + } + public static long getHeaderSize() { return headerSize; } public short getFieldAccessFlags(int index) { diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java index a69b3ceb0b8..22bdcf99638 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -861,6 +861,12 @@ public class VM { return (flag == null) ? false: flag.getBool(); } + public boolean getCommandLineBooleanFlag(String name) { + Flag flag = getCommandLineFlag(name); + return (flag == null) ? Boolean.FALSE: + (flag.getBool()? Boolean.TRUE: Boolean.FALSE); + } + // returns null, if not available. public Flag[] getCommandLineFlags() { if (commandLineFlags == null) { diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java index 0638d139739..da5a6a01313 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java @@ -40,7 +40,7 @@ public final class DebugInfo { private final BytecodePosition bytecodePosition; private ReferenceMap referenceMap; - @SuppressWarnings("unused") private final VirtualObject[] virtualObjectMapping; + private final VirtualObject[] virtualObjectMapping; private RegisterSaveLayout calleeSaveInfo; /** @@ -102,6 +102,10 @@ public final class DebugInfo { return referenceMap; } + public VirtualObject[] getVirtualObjectMapping() { + return virtualObjectMapping; + } + /** * Sets the map from the registers (in the caller's frame) to the slots where they are saved in * the current frame. diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java index 1be9c651e74..f92f91b7c78 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java @@ -333,7 +333,7 @@ final class CompilerToVM { * {@link HotSpotVMConfig#codeInstallResultDependenciesInvalid}. * @throws JVMCIError if there is something wrong with the compiled code or the metadata */ - public native int getMetadata(TargetDescription target, HotSpotCompiledCode compiledCode, HotSpotMetaData metaData); + native int getMetadata(TargetDescription target, HotSpotCompiledCode compiledCode, HotSpotMetaData metaData); /** * Resets all compilation statistics. @@ -604,6 +604,14 @@ final class CompilerToVM { */ native int methodDataProfileDataSize(long metaspaceMethodData, int position); + /** + * Gets the fingerprint for a given Klass* + * + * @param metaspaceKlass + * @return the value of the fingerprint (zero for arrays and synthetic classes). + */ + native long getFingerprint(long metaspaceKlass); + /** * Return the amount of native stack required for the interpreter frames represented by * {@code frame}. This is used when emitting the stack banging code to ensure that there is diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index 95c4b44bb61..f6c97ecb07f 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -96,7 +96,8 @@ public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider { TraceMethodDataFilter(String.class, null, "Enables tracing of profiling info when read by JVMCI.", "Empty value: trace all methods", - "Non-empty value: trace methods whose fully qualified name contains the value."); + "Non-empty value: trace methods whose fully qualified name contains the value."), + UseProfilingInformation(Boolean.class, true, ""); // @formatter:on /** diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java index 300e57b7168..5bd5014cdd8 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java @@ -22,38 +22,51 @@ */ package jdk.vm.ci.hotspot; -/** - * Encapsulates the VM metadata generated by {@link CompilerToVM#getMetadata}. - */ +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; + +import jdk.vm.ci.code.TargetDescription; + public class HotSpotMetaData { - @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] pcDescBytes; - @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] scopesDescBytes; - @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] relocBytes; - @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] exceptionBytes; - @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] oopMaps; - @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private String[] metadata; + private byte[] pcDescBytes; + private byte[] scopesDescBytes; + private byte[] relocBytes; + private byte[] exceptionBytes; + private byte[] oopMaps; + private String[] metadata; + + public HotSpotMetaData(TargetDescription target, HotSpotCompiledCode compiledMethod) { + // Assign the fields default values... + pcDescBytes = new byte[0]; + scopesDescBytes = new byte[0]; + relocBytes = new byte[0]; + exceptionBytes = new byte[0]; + oopMaps = new byte[0]; + metadata = new String[0]; + // ...some of them will be overwritten by the VM: + runtime().getCompilerToVM().getMetadata(target, compiledMethod, this); + } public byte[] pcDescBytes() { - return pcDescBytes != null ? pcDescBytes : new byte[0]; + return pcDescBytes; } public byte[] scopesDescBytes() { - return scopesDescBytes != null ? scopesDescBytes : new byte[0]; + return scopesDescBytes; } public byte[] relocBytes() { - return relocBytes != null ? relocBytes : new byte[0]; + return relocBytes; } public byte[] exceptionBytes() { - return exceptionBytes != null ? exceptionBytes : new byte[0]; + return exceptionBytes; } public byte[] oopMaps() { - return oopMaps != null ? oopMaps : new byte[0]; + return oopMaps; } public String[] metadataEntries() { - return metadata != null ? metadata : new String[0]; + return metadata; } } diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index e275b2ecaa5..ad4c67d0275 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -430,7 +430,7 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) { ProfilingInfo info; - if (methodData == null) { + if (Option.UseProfilingInformation.getBoolean() && methodData == null) { long metaspaceMethodData = UNSAFE.getAddress(metaspaceMethod + config().methodDataOffset); if (metaspaceMethodData != 0) { methodData = new HotSpotMethodData(metaspaceMethodData, this); diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java index 4ee2991a981..9028194e0df 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java @@ -103,6 +103,8 @@ public interface HotSpotResolvedObjectType extends ResolvedJavaType { int layoutHelper(); + long getFingerprint(); + HotSpotResolvedObjectType getEnclosingType(); ResolvedJavaMethod getClassInitializer(); diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index a7af6a61935..a0a3bc7a7a5 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -478,6 +478,11 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem return UNSAFE.getInt(getMetaspaceKlass() + config.klassLayoutHelperOffset); } + @Override + public long getFingerprint() { + return compilerToVM().getFingerprint(getMetaspaceKlass()); + } + synchronized HotSpotResolvedJavaMethod createMethod(long metaspaceMethod) { HotSpotResolvedJavaMethodImpl method = null; if (methodCache == null) { diff --git a/hotspot/src/jdk.vm.ci/share/classes/module-info.java b/hotspot/src/jdk.vm.ci/share/classes/module-info.java index f1a766e43f5..744442b1cdb 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/module-info.java +++ b/hotspot/src/jdk.vm.ci/share/classes/module-info.java @@ -30,9 +30,40 @@ module jdk.vm.ci { uses jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory; provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with - jdk.vm.ci.hotspot.aarch64.AArch64HotSpotJVMCIBackendFactory; - provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with - jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory; - provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with + jdk.vm.ci.hotspot.aarch64.AArch64HotSpotJVMCIBackendFactory, + jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory, jdk.vm.ci.hotspot.sparc.SPARCHotSpotJVMCIBackendFactory; + + exports jdk.vm.ci.aarch64 to + jdk.vm.compiler; + exports jdk.vm.ci.amd64 to + jdk.aot, + jdk.vm.compiler; + exports jdk.vm.ci.code to + jdk.aot, + jdk.vm.compiler; + exports jdk.vm.ci.code.site to + jdk.aot, + jdk.vm.compiler; + exports jdk.vm.ci.code.stack to + jdk.vm.compiler; + exports jdk.vm.ci.common to + jdk.vm.compiler; + exports jdk.vm.ci.hotspot to + jdk.aot, + jdk.vm.compiler; + exports jdk.vm.ci.hotspot.aarch64 to + jdk.vm.compiler; + exports jdk.vm.ci.hotspot.amd64 to + jdk.vm.compiler; + exports jdk.vm.ci.hotspot.sparc to + jdk.vm.compiler; + exports jdk.vm.ci.meta to + jdk.aot, + jdk.vm.compiler; + exports jdk.vm.ci.runtime to + jdk.aot, + jdk.vm.compiler; + exports jdk.vm.ci.sparc to + jdk.vm.compiler; } diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/.project b/hotspot/src/jdk.vm.compiler/.mx.graal/.project new file mode 100644 index 00000000000..b0404dbe290 --- /dev/null +++ b/hotspot/src/jdk.vm.compiler/.mx.graal/.project @@ -0,0 +1,19 @@ + + + mx.graal + + + mx + mx.jvmci + + + + org.python.pydev.PyDevBuilder + + + + + + org.python.pydev.pythonNature + + diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/.pydevproject b/hotspot/src/jdk.vm.compiler/.mx.graal/.pydevproject new file mode 100644 index 00000000000..c2a81b0a6a5 --- /dev/null +++ b/hotspot/src/jdk.vm.compiler/.mx.graal/.pydevproject @@ -0,0 +1,11 @@ + + +Default +python 2.7 + +/mx.graal +/mx.graal +/mx.graal + + + diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/eclipse-settings/org.eclipse.jdt.core.prefs b/hotspot/src/jdk.vm.compiler/.mx.graal/eclipse-settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..1c652f69b64 --- /dev/null +++ b/hotspot/src/jdk.vm.compiler/.mx.graal/eclipse-settings/org.eclipse.jdt.core.prefs @@ -0,0 +1 @@ +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=disabled diff --git a/jdk/test/java/net/ServerSocket/AcceptCauseFileDescriptorLeak.sh b/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal.py similarity index 58% rename from jdk/test/java/net/ServerSocket/AcceptCauseFileDescriptorLeak.sh rename to hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal.py index cd67e5720a5..906d8e08da1 100644 --- a/jdk/test/java/net/ServerSocket/AcceptCauseFileDescriptorLeak.sh +++ b/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal.py @@ -1,5 +1,7 @@ # -# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +# ---------------------------------------------------------------------------------------------------- +# +# Copyright (c) 2007, 2015, 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 @@ -20,29 +22,12 @@ # or visit www.oracle.com if you need additional information or have any # questions. # +# ---------------------------------------------------------------------------------------------------- -# @test -# @bug 6368984 -# @summary configuring unconnected Socket before passing to implAccept can cause fd leak -# @build AcceptCauseFileDescriptorLeak -# @run shell AcceptCauseFileDescriptorLeak.sh +import mx +if mx.get_jdk(tag='default').javaCompliance < "1.9": + mx.abort('JAVA_HOME is not a JDK9: ' + mx.get_jdk(tag='default').home) -OS=`uname -s` -case "$OS" in - Windows_* | CYGWIN* ) - echo "ulimit not on Windows" - exit 0 - ;; - * ) - CLASSPATH=${TESTCLASSES}:${TESTSRC} - ;; -esac -export CLASSPATH +from mx_graal_9 import mx_post_parse_cmd_line, run_vm, get_vm, isJVMCIEnabled # pylint: disable=unused-import -# hard limit needs to be less than 1024 for this bug -NOFILES=`ulimit -n -H` -if [ "$NOFILES" = "unlimited" ] || [ $NOFILES -ge 1024 ]; then - ulimit -n 1024 -fi - -${TESTJAVA}/bin/java ${TESTVMOPTS} AcceptCauseFileDescriptorLeak +import mx_graal_bench # pylint: disable=unused-import diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal_9.py b/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal_9.py new file mode 100644 index 00000000000..2d93ed06a14 --- /dev/null +++ b/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal_9.py @@ -0,0 +1,436 @@ +# +# ---------------------------------------------------------------------------------------------------- +# +# Copyright (c) 2007, 2015, 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. +# +# ---------------------------------------------------------------------------------------------------- + +import os +from os.path import join, dirname, basename, exists, abspath +from argparse import ArgumentParser +import sanitycheck +import re + +import mx +from mx_gate import Task +from sanitycheck import _noneAsEmptyList + +from mx_unittest import unittest +from mx_graal_bench import dacapo +import mx_gate +import mx_unittest + +_suite = mx.suite('graal') + +_jdk = mx.get_jdk(tag='default') +assert _jdk.javaCompliance >= "1.9" + +def isJVMCIEnabled(vm): + return True + +_jvmciModes = { + 'hosted' : ['-XX:+UnlockExperimentalVMOptions', '-XX:+EnableJVMCI'], + 'jit' : ['-XX:+UnlockExperimentalVMOptions', '-XX:+EnableJVMCI', '-XX:+UseJVMCICompiler'], + 'disabled' : [] +} + +def get_vm(): + """ + Gets the name of the currently selected JVM variant. + """ + return 'server' + +class JVMCIMode: + """ + A context manager for setting the current JVMCI mode. + """ + def __init__(self, jvmciMode=None): + self.update(jvmciMode) + + def update(self, jvmciMode=None): + assert jvmciMode is None or jvmciMode in _jvmciModes, jvmciMode + self.jvmciMode = jvmciMode or _vm.jvmciMode + + def __enter__(self): + global _vm + self.previousVm = _vm + _vm = self + + def __exit__(self, exc_type, exc_value, traceback): + global _vm + _vm = self.previousVm + +_vm = JVMCIMode(jvmciMode='jit') + +class BootClasspathDist(object): + """ + Extra info for a Distribution that must be put onto the boot class path. + """ + def __init__(self, name): + self._name = name + + def dist(self): + return mx.distribution(self._name) + + def get_classpath_repr(self): + return self.dist().classpath_repr() + +_compilers = ['graal-economy', 'graal'] +_bootClasspathDists = [ + BootClasspathDist('GRAAL'), +] + +def add_compiler(compilerName): + _compilers.append(compilerName) + +def add_boot_classpath_dist(dist): + _bootClasspathDists.append(dist) + +mx_gate.add_jacoco_includes(['org.graalvm.compiler.*']) +mx_gate.add_jacoco_excluded_annotations(['@Snippet', '@ClassSubstitution']) + +# This is different than the 'jmh' commmand in that it +# looks for internal JMH benchmarks (i.e. those that +# depend on the JMH library). +def microbench(args): + """run JMH microbenchmark projects""" + parser = ArgumentParser(prog='mx microbench', description=microbench.__doc__, + usage="%(prog)s [command options|VM options] [-- [JMH options]]") + parser.add_argument('--jar', help='Explicitly specify micro-benchmark location') + known_args, args = parser.parse_known_args(args) + + vmArgs, jmhArgs = mx.extract_VM_args(args, useDoubleDash=True) + + # look for -f in JMH arguments + forking = True + for i in range(len(jmhArgs)): + arg = jmhArgs[i] + if arg.startswith('-f'): + if arg == '-f' and (i+1) < len(jmhArgs): + arg += jmhArgs[i+1] + try: + if int(arg[2:]) == 0: + forking = False + except ValueError: + pass + + if known_args.jar: + # use the specified jar + args = ['-jar', known_args.jar] + if not forking: + args += vmArgs + else: + # find all projects with a direct JMH dependency + jmhProjects = [] + for p in mx.projects_opt_limit_to_suites(): + if 'JMH' in [x.name for x in p.deps]: + jmhProjects.append(p.name) + cp = mx.classpath(jmhProjects) + + # execute JMH runner + args = ['-cp', cp] + if not forking: + args += vmArgs + args += ['org.openjdk.jmh.Main'] + + if forking: + jvm = get_vm() + def quoteSpace(s): + if " " in s: + return '"' + s + '"' + return s + + forkedVmArgs = map(quoteSpace, _parseVmArgs(_jdk, vmArgs)) + args += ['--jvmArgsPrepend', ' '.join(['-' + jvm] + forkedVmArgs)] + run_vm(args + jmhArgs) + +def ctw(args, extraVMarguments=None): + """run CompileTheWorld""" + + defaultCtwopts = '-Inline' + + parser = ArgumentParser(prog='mx ctw') + parser.add_argument('--ctwopts', action='store', help='space separated JVMCI options used for CTW compilations (default: --ctwopts="' + defaultCtwopts + '")', default=defaultCtwopts, metavar='') + parser.add_argument('--cp', '--jar', action='store', help='jar or class path denoting classes to compile', metavar='') + + args, vmargs = parser.parse_known_args(args) + + if args.ctwopts: + # Replace spaces with '#' since -G: options cannot contain spaces + vmargs.append('-G:CompileTheWorldConfig=' + re.sub(r'\s+', '#', args.ctwopts)) + + if args.cp: + cp = os.path.abspath(args.cp) + else: + cp = join(_jdk.home, 'lib', 'modules', 'bootmodules.jimage') + vmargs.append('-G:CompileTheWorldExcludeMethodFilter=sun.awt.X11.*.*') + + # suppress menubar and dock when running on Mac; exclude x11 classes as they may cause vm crashes (on Solaris) + vmargs = ['-Djava.awt.headless=true'] + vmargs + + if _vm.jvmciMode == 'disabled': + vmargs += ['-XX:+CompileTheWorld', '-Xbootclasspath/p:' + cp] + else: + if _vm.jvmciMode == 'jit': + vmargs += ['-XX:+BootstrapJVMCI'] + vmargs += ['-G:CompileTheWorldClasspath=' + cp, 'org.graalvm.compiler.hotspot.CompileTheWorld'] + + run_vm(vmargs + _noneAsEmptyList(extraVMarguments)) + +class UnitTestRun: + def __init__(self, name, args): + self.name = name + self.args = args + + def run(self, suites, tasks, extraVMarguments=None): + for suite in suites: + with Task(self.name + ': hosted-release ' + suite, tasks) as t: + if t: unittest(['--suite', suite, '--enable-timing', '--verbose', '--fail-fast'] + self.args + _noneAsEmptyList(extraVMarguments)) + +class BootstrapTest: + def __init__(self, name, args, suppress=None): + self.name = name + self.args = args + self.suppress = suppress + + def run(self, tasks, extraVMarguments=None): + with JVMCIMode('jit'): + with Task(self.name, tasks) as t: + if t: + if self.suppress: + out = mx.DuplicateSuppressingStream(self.suppress).write + else: + out = None + run_vm(self.args + _noneAsEmptyList(extraVMarguments) + ['-XX:-TieredCompilation', '-XX:+BootstrapJVMCI', '-version'], out=out) + +class MicrobenchRun: + def __init__(self, name, args): + self.name = name + self.args = args + + def run(self, tasks, extraVMarguments=None): + with Task(self.name + ': hosted-product ', tasks) as t: + if t: microbench(_noneAsEmptyList(extraVMarguments) + ['--'] + self.args) + +def compiler_gate_runner(suites, unit_test_runs, bootstrap_tests, tasks, extraVMarguments=None): + + # Run unit tests in hosted mode + with JVMCIMode('hosted'): + for r in unit_test_runs: + r.run(suites, tasks, extraVMarguments) + + # Run microbench in hosted mode (only for testing the JMH setup) + with JVMCIMode('hosted'): + for r in [MicrobenchRun('Microbench', ['TestJMH'])]: + r.run(tasks, extraVMarguments) + + # Run ctw against rt.jar on server-hosted-jvmci + with JVMCIMode('hosted'): + with Task('CTW:hosted', tasks) as t: + if t: ctw(['--ctwopts', '-Inline +ExitVMOnException', '-esa', '-G:+CompileTheWorldMultiThreaded', '-G:-InlineDuringParsing', '-G:-CompileTheWorldVerbose', '-XX:ReservedCodeCacheSize=300m'], _noneAsEmptyList(extraVMarguments)) + + # bootstrap tests + for b in bootstrap_tests: + b.run(tasks, extraVMarguments) + + # run dacapo sanitychecks + for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel='release', extraVmArguments=extraVMarguments) \ + + sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel='release', extraVmArguments=extraVMarguments): + with Task(str(test) + ':' + 'release', tasks) as t: + if t and not test.test('jvmci'): + t.abort(test.name + ' Failed') + + # ensure -Xbatch still works + with JVMCIMode('jit'): + with Task('DaCapo_pmd:BatchMode', tasks) as t: + if t: dacapo(_noneAsEmptyList(extraVMarguments) + ['-Xbatch', 'pmd']) + + # ensure benchmark counters still work + with JVMCIMode('jit'): + with Task('DaCapo_pmd:BenchmarkCounters:product', tasks) as t: + if t: dacapo(_noneAsEmptyList(extraVMarguments) + ['-G:+LIRProfileMoves', '-G:+GenericDynamicCounters', '-XX:JVMCICounterSize=10', 'pmd']) + + # ensure -Xcomp still works + with JVMCIMode('jit'): + with Task('XCompMode:product', tasks) as t: + if t: run_vm(_noneAsEmptyList(extraVMarguments) + ['-Xcomp', '-version']) + + +graal_unit_test_runs = [ + UnitTestRun('UnitTests', []), +] + +_registers = 'o0,o1,o2,o3,f8,f9,d32,d34' if mx.get_arch() == 'sparcv9' else 'rbx,r11,r10,r14,xmm3,xmm11,xmm14' + +graal_bootstrap_tests = [ + BootstrapTest('BootstrapWithSystemAssertions', ['-esa']), + BootstrapTest('BootstrapWithSystemAssertionsNoCoop', ['-esa', '-XX:-UseCompressedOops', '-G:+ExitVMOnException']), + BootstrapTest('BootstrapWithGCVerification', ['-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-G:+ExitVMOnException'], suppress=['VerifyAfterGC:', 'VerifyBeforeGC:']), + BootstrapTest('BootstrapWithG1GCVerification', ['-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-G:+ExitVMOnException'], suppress=['VerifyAfterGC:', 'VerifyBeforeGC:']), + BootstrapTest('BootstrapEconomyWithSystemAssertions', ['-esa', '-Djvmci.compiler=graal-economy', '-G:+ExitVMOnException']), + BootstrapTest('BootstrapWithExceptionEdges', ['-esa', '-G:+StressInvokeWithExceptionNode', '-G:+ExitVMOnException']), + BootstrapTest('BootstrapWithRegisterPressure', ['-esa', '-G:RegisterPressure=' + _registers, '-G:+ExitVMOnException', '-G:+LIRUnlockBackendRestart']), + BootstrapTest('BootstrapTraceRAWithRegisterPressure', ['-esa', '-G:+TraceRA', '-G:RegisterPressure=' + _registers, '-G:+ExitVMOnException', '-G:+LIRUnlockBackendRestart']), + BootstrapTest('BootstrapWithImmutableCode', ['-esa', '-G:+ImmutableCode', '-G:+VerifyPhases', '-G:+ExitVMOnException']), +] + +def _graal_gate_runner(args, tasks): + compiler_gate_runner(['graal'], graal_unit_test_runs, graal_bootstrap_tests, tasks, args.extra_vm_argument) + +mx_gate.add_gate_runner(_suite, _graal_gate_runner) +mx_gate.add_gate_argument('--extra-vm-argument', action='append', help='add extra vm argument to gate tasks if applicable (multiple occurrences allowed)') + +def _unittest_vm_launcher(vmArgs, mainClass, mainClassArgs): + run_vm(vmArgs + [mainClass] + mainClassArgs) + +mx_unittest.set_vm_launcher('JDK9 VM launcher', _unittest_vm_launcher) + +def _parseVmArgs(jdk, args, addDefaultArgs=True): + args = mx.expand_project_in_args(args, insitu=False) + jacocoArgs = mx_gate.get_jacoco_agent_args() + if jacocoArgs: + args = jacocoArgs + args + + # Support for -G: options + def translateGOption(arg): + if arg.startswith('-G:+'): + if '=' in arg: + mx.abort('Mixing + and = in -G: option specification: ' + arg) + arg = '-Dgraal.' + arg[len('-G:+'):] + '=true' + elif arg.startswith('-G:-'): + if '=' in arg: + mx.abort('Mixing - and = in -G: option specification: ' + arg) + arg = '-Dgraal.' + arg[len('-G:+'):] + '=false' + elif arg.startswith('-G:'): + if '=' not in arg: + mx.abort('Missing "=" in non-boolean -G: option specification: ' + arg) + arg = '-Dgraal.' + arg[len('-G:'):] + return arg + args = map(translateGOption, args) + + if '-G:+PrintFlags' in args and '-Xcomp' not in args: + mx.warn('Using -G:+PrintFlags may have no effect without -Xcomp as Graal initialization is lazy') + + bcp = [] + if _jvmciModes[_vm.jvmciMode]: + if _add_jvmci_to_bootclasspath: + bcp.append(mx.library('JVMCI').classpath_repr()) + bcp.extend([d.get_classpath_repr() for d in _bootClasspathDists]) + if bcp: + args = ['-Xbootclasspath/p:' + os.pathsep.join(bcp)] + args + + # Remove JVMCI from class path. It's only there to support compilation. + cpIndex, cp = mx.find_classpath_arg(args) + if cp: + jvmciLib = mx.library('JVMCI').path + cp = os.pathsep.join([e for e in cp.split(os.pathsep) if e != jvmciLib]) + args[cpIndex] = cp + + # Set the default JVMCI compiler + jvmciCompiler = _compilers[-1] + args = ['-Djvmci.compiler=' + jvmciCompiler] + args + + if '-version' in args: + ignoredArgs = args[args.index('-version') + 1:] + if len(ignoredArgs) > 0: + mx.log("Warning: The following options will be ignored by the vm because they come after the '-version' argument: " + ' '.join(ignoredArgs)) + return jdk.processArgs(args, addDefaultArgs=addDefaultArgs) + +def run_java(jdk, args, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, env=None, addDefaultArgs=True): + + args = _parseVmArgs(jdk, args, addDefaultArgs=addDefaultArgs) + + jvmciModeArgs = _jvmciModes[_vm.jvmciMode] + cmd = [jdk.java] + ['-' + get_vm()] + jvmciModeArgs + args + return mx.run(cmd, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd) + +_JVMCI_JDK_TAG = 'jvmci' + +class GraalJVMCI9JDKConfig(mx.JDKConfig): + def __init__(self, original): + self._original = original + mx.JDKConfig.__init__(self, original.home, tag=_JVMCI_JDK_TAG) + + def run_java(self, args, **kwArgs): + run_java(self._original, args, **kwArgs) + +class GraalJDKFactory(mx.JDKFactory): + def getJDKConfig(self): + return GraalJVMCI9JDKConfig(_jdk) + + def description(self): + return "JVMCI JDK with Graal" + +# This will override the 'generic' JVMCI JDK with a Graal JVMCI JDK that has +# support for -G style Graal options. +mx.addJDKFactory(_JVMCI_JDK_TAG, mx.JavaCompliance('9'), GraalJDKFactory()) + +def run_vm(args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, debugLevel=None, vmbuild=None): + """run a Java program by executing the java executable in a JVMCI JDK""" + + return run_java(_jdk, args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout) + +class GraalArchiveParticipant: + def __init__(self, dist): + self.dist = dist + + def __opened__(self, arc, srcArc, services): + self.services = services + self.arc = arc + + def __add__(self, arcname, contents): + if arcname.startswith('META-INF/providers/'): + provider = arcname[len('META-INF/providers/'):] + for service in contents.strip().split(os.linesep): + assert service + self.services.setdefault(service, []).append(provider) + return True + elif arcname.endswith('_OptionDescriptors.class'): + # Need to create service files for the providers of the + # jdk.vm.ci.options.Options service created by + # jdk.vm.ci.options.processor.OptionProcessor. + provider = arcname[:-len('.class'):].replace('/', '.') + self.services.setdefault('org.graalvm.compiler.options.OptionDescriptors', []).append(provider) + return False + + def __addsrc__(self, arcname, contents): + return False + + def __closing__(self): + pass + +mx.update_commands(_suite, { + 'vm': [run_vm, '[-options] class [args...]'], + 'ctw': [ctw, '[-vmoptions|noinline|nocomplex|full]'], + 'microbench' : [microbench, '[VM options] [-- [JMH options]]'], +}) + +mx.add_argument('-M', '--jvmci-mode', action='store', choices=sorted(_jvmciModes.viewkeys()), help='the JVM variant type to build/run (default: ' + _vm.jvmciMode + ')') + +def mx_post_parse_cmd_line(opts): + if opts.jvmci_mode is not None: + _vm.update(opts.jvmci_mode) + for dist in [d.dist() for d in _bootClasspathDists]: + dist.set_archiveparticipant(GraalArchiveParticipant(dist)) + +_add_jvmci_to_bootclasspath = False + diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal_bench.py b/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal_bench.py new file mode 100644 index 00000000000..e99e6deb25f --- /dev/null +++ b/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal_bench.py @@ -0,0 +1,256 @@ +# +# ---------------------------------------------------------------------------------------------------- +# +# Copyright (c) 2007, 2015, 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. +# +# ---------------------------------------------------------------------------------------------------- + +import sanitycheck +import itertools +import json + +import mx +import mx_graal + +def _run_benchmark(args, availableBenchmarks, runBenchmark): + + vmOpts, benchmarksAndOptions = mx.extract_VM_args(args, useDoubleDash=availableBenchmarks is None) + + if availableBenchmarks is None: + harnessArgs = benchmarksAndOptions + return runBenchmark(None, harnessArgs, vmOpts) + + if len(benchmarksAndOptions) == 0: + mx.abort('at least one benchmark name or "all" must be specified') + benchmarks = list(itertools.takewhile(lambda x: not x.startswith('-'), benchmarksAndOptions)) + harnessArgs = benchmarksAndOptions[len(benchmarks):] + + if 'all' in benchmarks: + benchmarks = availableBenchmarks + else: + for bm in benchmarks: + if bm not in availableBenchmarks: + mx.abort('unknown benchmark: ' + bm + '\nselect one of: ' + str(availableBenchmarks)) + + failed = [] + for bm in benchmarks: + if not runBenchmark(bm, harnessArgs, vmOpts): + failed.append(bm) + + if len(failed) != 0: + mx.abort('Benchmark failures: ' + str(failed)) + +def deoptalot(args): + """bootstrap a VM with DeoptimizeALot and VerifyOops on + + If the first argument is a number, the process will be repeated + this number of times. All other arguments are passed to the VM.""" + count = 1 + if len(args) > 0 and args[0].isdigit(): + count = int(args[0]) + del args[0] + + for _ in range(count): + if not mx_graal.run_vm(['-XX:-TieredCompilation', '-XX:+DeoptimizeALot', '-XX:+VerifyOops'] + args + ['-version']) == 0: + mx.abort("Failed") + +def longtests(args): + + deoptalot(['15', '-Xmx48m']) + + dacapo(['100', 'eclipse', '-esa']) + +def dacapo(args): + """run one or more DaCapo benchmarks""" + + def launcher(bm, harnessArgs, extraVmOpts): + return sanitycheck.getDacapo(bm, harnessArgs).test(mx_graal.get_vm(), extraVmOpts=extraVmOpts) + + _run_benchmark(args, sanitycheck.dacapoSanityWarmup.keys(), launcher) + +def scaladacapo(args): + """run one or more Scala DaCapo benchmarks""" + + def launcher(bm, harnessArgs, extraVmOpts): + return sanitycheck.getScalaDacapo(bm, harnessArgs).test(mx_graal.get_vm(), extraVmOpts=extraVmOpts) + + _run_benchmark(args, sanitycheck.dacapoScalaSanityWarmup.keys(), launcher) + + +""" +Extra benchmarks to run from 'bench()'. +""" +extraBenchmarks = [] + +def bench(args): + """run benchmarks and parse their output for results + + Results are JSON formated : {group : {benchmark : score}}.""" + resultFile = None + if '-resultfile' in args: + index = args.index('-resultfile') + if index + 1 < len(args): + resultFile = args[index + 1] + del args[index] + del args[index] + else: + mx.abort('-resultfile must be followed by a file name') + resultFileCSV = None + if '-resultfilecsv' in args: + index = args.index('-resultfilecsv') + if index + 1 < len(args): + resultFileCSV = args[index + 1] + del args[index] + del args[index] + else: + mx.abort('-resultfilecsv must be followed by a file name') + vm = mx_graal.get_vm() + if len(args) is 0: + args = ['all'] + + vmArgs = [arg for arg in args if arg.startswith('-')] + + def benchmarks_in_group(group): + prefix = group + ':' + return [a[len(prefix):] for a in args if a.startswith(prefix)] + + results = {} + benchmarks = [] + # DaCapo + if 'dacapo' in args or 'all' in args: + benchmarks += sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Benchmark) + else: + dacapos = benchmarks_in_group('dacapo') + for dacapo in dacapos: + if dacapo not in sanitycheck.dacapoSanityWarmup.keys(): + mx.abort('Unknown DaCapo : ' + dacapo) + iterations = sanitycheck.dacapoSanityWarmup[dacapo][sanitycheck.SanityCheckLevel.Benchmark] + if iterations > 0: + benchmarks += [sanitycheck.getDacapo(dacapo, ['-n', str(iterations)])] + + if 'scaladacapo' in args or 'all' in args: + benchmarks += sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Benchmark) + else: + scaladacapos = benchmarks_in_group('scaladacapo') + for scaladacapo in scaladacapos: + if scaladacapo not in sanitycheck.dacapoScalaSanityWarmup.keys(): + mx.abort('Unknown Scala DaCapo : ' + scaladacapo) + iterations = sanitycheck.dacapoScalaSanityWarmup[scaladacapo][sanitycheck.SanityCheckLevel.Benchmark] + if iterations > 0: + benchmarks += [sanitycheck.getScalaDacapo(scaladacapo, ['-n', str(iterations)])] + + # Bootstrap + if 'bootstrap' in args or 'all' in args: + benchmarks += sanitycheck.getBootstraps() + # SPECjvm2008 + if 'specjvm2008' in args or 'all' in args: + benchmarks += [sanitycheck.getSPECjvm2008(['-ikv', '-wt', '120', '-it', '120'])] + else: + specjvms = benchmarks_in_group('specjvm2008') + for specjvm in specjvms: + benchmarks += [sanitycheck.getSPECjvm2008(['-ikv', '-wt', '120', '-it', '120', specjvm])] + + if 'specjbb2005' in args or 'all' in args: + benchmarks += [sanitycheck.getSPECjbb2005()] + + if 'specjbb2013' in args: # or 'all' in args //currently not in default set + benchmarks += [sanitycheck.getSPECjbb2013()] + + if 'ctw-full' in args: + benchmarks.append(sanitycheck.getCTW(vm, sanitycheck.CTWMode.Full)) + if 'ctw-noinline' in args: + benchmarks.append(sanitycheck.getCTW(vm, sanitycheck.CTWMode.NoInline)) + + for f in extraBenchmarks: + f(args, vm, benchmarks) + + for test in benchmarks: + for (groupName, res) in test.bench(vm, extraVmOpts=vmArgs).items(): + group = results.setdefault(groupName, {}) + group.update(res) + mx.log(json.dumps(results)) + if resultFile: + with open(resultFile, 'w') as f: + f.write(json.dumps(results)) + if resultFileCSV: + with open(resultFileCSV, 'w') as f: + for key1, value1 in results.iteritems(): + f.write('%s;\n' % (str(key1))) + for key2, value2 in sorted(value1.iteritems()): + f.write('%s; %s;\n' % (str(key2), str(value2))) + +def specjvm2008(args): + """run one or more SPECjvm2008 benchmarks""" + + def launcher(bm, harnessArgs, extraVmOpts): + return sanitycheck.getSPECjvm2008(harnessArgs + [bm]).bench(mx_graal.get_vm(), extraVmOpts=extraVmOpts) + + availableBenchmarks = set(sanitycheck.specjvm2008Names) + if "all" not in args: + # only add benchmark groups if we are not running "all" + for name in sanitycheck.specjvm2008Names: + parts = name.rsplit('.', 1) + if len(parts) > 1: + assert len(parts) == 2 + group = parts[0] + availableBenchmarks.add(group) + + _run_benchmark(args, sorted(availableBenchmarks), launcher) + +def specjbb2013(args): + """run the composite SPECjbb2013 benchmark""" + + def launcher(bm, harnessArgs, extraVmOpts): + assert bm is None + return sanitycheck.getSPECjbb2013(harnessArgs).bench(mx_graal.get_vm(), extraVmOpts=extraVmOpts) + + _run_benchmark(args, None, launcher) + +def specjbb2015(args): + """run the composite SPECjbb2015 benchmark""" + + def launcher(bm, harnessArgs, extraVmOpts): + assert bm is None + return sanitycheck.getSPECjbb2015(harnessArgs).bench(mx_graal.get_vm(), extraVmOpts=extraVmOpts) + + _run_benchmark(args, None, launcher) + +def specjbb2005(args): + """run the composite SPECjbb2005 benchmark""" + + def launcher(bm, harnessArgs, extraVmOpts): + assert bm is None + return sanitycheck.getSPECjbb2005(harnessArgs).bench(mx_graal.get_vm(), extraVmOpts=extraVmOpts) + + _run_benchmark(args, None, launcher) + +mx.update_commands(mx.suite('graal'), { + 'dacapo': [dacapo, '[VM options] benchmarks...|"all" [DaCapo options]'], + 'scaladacapo': [scaladacapo, '[VM options] benchmarks...|"all" [Scala DaCapo options]'], + 'specjvm2008': [specjvm2008, '[VM options] benchmarks...|"all" [SPECjvm2008 options]'], + 'specjbb2013': [specjbb2013, '[VM options] [-- [SPECjbb2013 options]]'], + 'specjbb2015': [specjbb2015, '[VM options] [-- [SPECjbb2015 options]]'], + 'specjbb2005': [specjbb2005, '[VM options] [-- [SPECjbb2005 options]]'], + 'bench' : [bench, '[-resultfile file] [all(default)|dacapo|specjvm2008|bootstrap]'], + 'deoptalot' : [deoptalot, '[n]'], + 'longtests' : [longtests, ''], +}) diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/outputparser.py b/hotspot/src/jdk.vm.compiler/.mx.graal/outputparser.py new file mode 100644 index 00000000000..c2dbd6f05d6 --- /dev/null +++ b/hotspot/src/jdk.vm.compiler/.mx.graal/outputparser.py @@ -0,0 +1,71 @@ +# ---------------------------------------------------------------------------------------------------- +# +# Copyright (c) 2007, 2012, 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. +# +# ---------------------------------------------------------------------------------------------------- + +import re + +class OutputParser: + + def __init__(self): + self.matchers = [] + + def addMatcher(self, matcher): + self.matchers.append(matcher) + + def parse(self, output): + valueMaps = [] + for matcher in self.matchers: + matcher.parse(output, valueMaps) + return valueMaps + +""" +Produces a value map for each match of a given regular expression +in some text. The value map is specified by a template map +where each key and value in the template map is either a constant +value or a named group in the regular expression. The latter is +given as the group name enclosed in '<' and '>'. +""" +class ValuesMatcher: + + def __init__(self, regex, valuesTemplate): + assert isinstance(valuesTemplate, dict) + self.regex = regex + self.valuesTemplate = valuesTemplate + + def parse(self, text, valueMaps): + for match in self.regex.finditer(text): + valueMap = {} + for keyTemplate, valueTemplate in self.valuesTemplate.items(): + key = self.get_template_value(match, keyTemplate) + value = self.get_template_value(match, valueTemplate) + assert not valueMap.has_key(key), key + valueMap[key] = value + valueMaps.append(valueMap) + + def get_template_value(self, match, template): + def replace_var(m): + groupName = m.group(1) + return match.group(groupName) + + return re.sub(r'<([\w]+)>', replace_var, template) diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/sanitycheck.py b/hotspot/src/jdk.vm.compiler/.mx.graal/sanitycheck.py new file mode 100644 index 00000000000..7d9533caa6f --- /dev/null +++ b/hotspot/src/jdk.vm.compiler/.mx.graal/sanitycheck.py @@ -0,0 +1,453 @@ +# ---------------------------------------------------------------------------------------------------- +# +# Copyright (c) 2007, 2012, 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. +# +# ---------------------------------------------------------------------------------------------------- + +from outputparser import OutputParser, ValuesMatcher +import re, mx, mx_graal, os, sys, StringIO, subprocess +from os.path import isfile, join, exists + +gc = 'UseSerialGC' + +dacapoSanityWarmup = { + 'avrora': [0, 0, 3, 6, 13], + 'batik': [0, 0, 5, 5, 20], + 'eclipse': [0, 0, 0, 0, 0], + 'fop': [4, 8, 10, 20, 30], + 'h2': [0, 0, 5, 5, 8], + 'jython': [0, 0, 5, 10, 13], + 'luindex': [0, 0, 5, 10, 10], + 'lusearch': [0, 4, 5, 5, 8], + 'pmd': [0, 0, 5, 10, 13], + 'sunflow': [0, 2, 5, 10, 15], + 'tomcat': [0, 0, 5, 10, 15], + 'tradebeans': [0, 0, 5, 10, 13], + 'tradesoap': [0, 0, 5, 10, 15], + 'xalan': [0, 0, 5, 10, 18], +} + +dacapoScalaSanityWarmup = { + 'actors': [0, 0, 2, 5, 5], + 'apparat': [0, 0, 2, 5, 5], + 'factorie': [0, 0, 2, 5, 5], + 'kiama': [0, 4, 3, 13, 15], + 'scalac': [0, 0, 5, 15, 20], + 'scaladoc': [0, 0, 5, 15, 15], + 'scalap': [0, 0, 5, 15, 20], + 'scalariform':[0, 0, 6, 15, 20], + 'scalatest': [0, 0, 2, 10, 12], + 'scalaxb': [0, 0, 5, 15, 25], +# (gdub) specs sometimes returns a non-zero value event though there is no apparent failure + 'specs': [0, 0, 0, 0, 0], + 'tmt': [0, 0, 3, 10, 12] +} + +dacapoGateBuildLevels = { + 'avrora': ['product', 'fastdebug', 'debug'], + 'batik': ['product', 'fastdebug', 'debug'], + # (lewurm): does not work with JDK8 + 'eclipse': [], + 'fop': ['fastdebug', 'debug'], + 'h2': ['product', 'fastdebug', 'debug'], + 'jython': ['product', 'fastdebug', 'debug'], + 'luindex': ['product', 'fastdebug', 'debug'], + 'lusearch': ['product'], + 'pmd': ['product', 'fastdebug', 'debug'], + 'sunflow': ['fastdebug', 'debug'], + 'tomcat': ['product', 'fastdebug', 'debug'], + 'tradebeans': ['product', 'fastdebug', 'debug'], + # tradesoap is too unreliable for the gate, often crashing with concurrency problems: + # http://sourceforge.net/p/dacapobench/bugs/99/ + 'tradesoap': [], + 'xalan': ['product', 'fastdebug', 'debug'], +} + +dacapoScalaGateBuildLevels = { + 'actors': ['product', 'fastdebug', 'debug'], + 'apparat': ['product', 'fastdebug', 'debug'], + 'factorie': ['product', 'fastdebug', 'debug'], + 'kiama': ['fastdebug', 'debug'], + 'scalac': ['product', 'fastdebug', 'debug'], + 'scaladoc': ['product', 'fastdebug', 'debug'], + 'scalap': ['product', 'fastdebug', 'debug'], + 'scalariform':['product', 'fastdebug', 'debug'], + 'scalatest': ['product', 'fastdebug', 'debug'], + 'scalaxb': ['product', 'fastdebug', 'debug'], + 'specs': ['product', 'fastdebug', 'debug'], + 'tmt': ['product', 'fastdebug', 'debug'], +} + +specjvm2008Names = [ + 'startup.helloworld', + 'startup.compiler.compiler', + 'startup.compiler.sunflow', + 'startup.compress', + 'startup.crypto.aes', + 'startup.crypto.rsa', + 'startup.crypto.signverify', + 'startup.mpegaudio', + 'startup.scimark.fft', + 'startup.scimark.lu', + 'startup.scimark.monte_carlo', + 'startup.scimark.sor', + 'startup.scimark.sparse', + 'startup.serial', + 'startup.sunflow', + 'startup.xml.transform', + 'startup.xml.validation', + 'compiler.compiler', + 'compiler.sunflow', + 'compress', + 'crypto.aes', + 'crypto.rsa', + 'crypto.signverify', + 'derby', + 'mpegaudio', + 'scimark.fft.large', + 'scimark.lu.large', + 'scimark.sor.large', + 'scimark.sparse.large', + 'scimark.fft.small', + 'scimark.lu.small', + 'scimark.sor.small', + 'scimark.sparse.small', + 'scimark.monte_carlo', + 'serial', + 'sunflow', + 'xml.transform', + 'xml.validation' +] + +def _noneAsEmptyList(a): + if a is None: + return [] + return a + +class SanityCheckLevel: + Fast, Gate, Normal, Extensive, Benchmark = range(5) + +def getSPECjbb2005(benchArgs=None): + benchArgs = [] if benchArgs is None else benchArgs + + specjbb2005 = mx.get_env('SPECJBB2005') + if specjbb2005 is None or not exists(join(specjbb2005, 'jbb.jar')): + mx.abort('Please set the SPECJBB2005 environment variable to a SPECjbb2005 directory') + + score = re.compile(r"^Valid run, Score is (?P[0-9]+)$", re.MULTILINE) + error = re.compile(r"VALIDATION ERROR") + success = re.compile(r"^Valid run, Score is [0-9]+$", re.MULTILINE) + matcher = ValuesMatcher(score, {'group' : 'SPECjbb2005', 'name' : 'score', 'score' : ''}) + classpath = ['jbb.jar', 'check.jar'] + return Test("SPECjbb2005", ['spec.jbb.JBBmain', '-propfile', 'SPECjbb.props'] + benchArgs, [success], [error], [matcher], vmOpts=['-Xms3g', '-XX:+' + gc, '-XX:-UseCompressedOops', '-cp', os.pathsep.join(classpath)], defaultCwd=specjbb2005) + +def getSPECjbb2013(benchArgs=None): + + specjbb2013 = mx.get_env('SPECJBB2013') + if specjbb2013 is None or not exists(join(specjbb2013, 'specjbb2013.jar')): + mx.abort('Please set the SPECJBB2013 environment variable to a SPECjbb2013 directory') + + jops = re.compile(r"^RUN RESULT: hbIR \(max attempted\) = [0-9]+, hbIR \(settled\) = [0-9]+, max-jOPS = (?P[0-9]+), critical-jOPS = (?P[0-9]+)$", re.MULTILINE) + # error? + success = re.compile(r"org.spec.jbb.controller: Run finished", re.MULTILINE) + matcherMax = ValuesMatcher(jops, {'group' : 'SPECjbb2013', 'name' : 'max', 'score' : ''}) + matcherCritical = ValuesMatcher(jops, {'group' : 'SPECjbb2013', 'name' : 'critical', 'score' : ''}) + return Test("SPECjbb2013", ['-jar', 'specjbb2013.jar', '-m', 'composite'] + + _noneAsEmptyList(benchArgs), [success], [], [matcherCritical, matcherMax], + vmOpts=['-Xmx6g', '-Xms6g', '-Xmn3g', '-XX:+UseParallelOldGC', '-XX:-UseAdaptiveSizePolicy', '-XX:-UseBiasedLocking', '-XX:-UseCompressedOops'], defaultCwd=specjbb2013) + +def getSPECjbb2015(benchArgs=None): + + specjbb2015 = mx.get_env('SPECJBB2015') + if specjbb2015 is None or not exists(join(specjbb2015, 'specjbb2015.jar')): + mx.abort('Please set the SPECJBB2015 environment variable to a SPECjbb2015 directory') + + jops = re.compile(r"^RUN RESULT: hbIR \(max attempted\) = [0-9]+, hbIR \(settled\) = [0-9]+, max-jOPS = (?P[0-9]+), critical-jOPS = (?P[0-9]+)$", re.MULTILINE) + # error? + success = re.compile(r"org.spec.jbb.controller: Run finished", re.MULTILINE) + matcherMax = ValuesMatcher(jops, {'group' : 'SPECjbb2015', 'name' : 'max', 'score' : ''}) + matcherCritical = ValuesMatcher(jops, {'group' : 'SPECjbb2015', 'name' : 'critical', 'score' : ''}) + return Test("SPECjbb2015", ['-jar', 'specjbb2015.jar', '-m', 'composite'] + + _noneAsEmptyList(benchArgs), [success], [], [matcherCritical, matcherMax], + vmOpts=['-Xmx6g', '-Xms6g', '-Xmn3g', '-XX:+UseParallelOldGC', '-XX:-UseAdaptiveSizePolicy', '-XX:-UseBiasedLocking', '-XX:-UseCompressedOops'], defaultCwd=specjbb2015) + +def getSPECjvm2008(benchArgs=None): + + specjvm2008 = mx.get_env('SPECJVM2008') + if specjvm2008 is None or not exists(join(specjvm2008, 'SPECjvm2008.jar')): + mx.abort('Please set the SPECJVM2008 environment variable to a SPECjvm2008 directory') + + score = re.compile(r"^(Score on|Noncompliant) (?P[a-zA-Z0-9\._]+)( result)?: (?P[0-9]+((,|\.)[0-9]+)?)( SPECjvm2008 Base)? ops/m$", re.MULTILINE) + error = re.compile(r"^Errors in benchmark: ", re.MULTILINE) + # The ' ops/m' at the end of the success string is important : it's how you can tell valid and invalid runs apart + success = re.compile(r"^(Noncompliant c|C)omposite result: [0-9]+((,|\.)[0-9]+)?( SPECjvm2008 (Base|Peak))? ops/m$", re.MULTILINE) + matcher = ValuesMatcher(score, {'group' : 'SPECjvm2008', 'name' : '', 'score' : ''}) + + return Test("SPECjvm2008", ['-jar', 'SPECjvm2008.jar'] + _noneAsEmptyList(benchArgs), [success], [error], [matcher], vmOpts=['-Xms3g', '-XX:+' + gc, '-XX:-UseCompressedOops'], defaultCwd=specjvm2008) + +def getDacapos(level=SanityCheckLevel.Normal, gateBuildLevel=None, dacapoArgs=None, extraVmArguments=None): + checks = [] + + for (bench, ns) in dacapoSanityWarmup.items(): + if ns[level] > 0: + if gateBuildLevel is None or gateBuildLevel in dacapoGateBuildLevels[bench]: + checks.append(getDacapo(bench, ['-n', str(ns[level])] + _noneAsEmptyList(dacapoArgs), extraVmArguments=extraVmArguments)) + + return checks + +def getDacapo(name, dacapoArgs=None, extraVmArguments=None): + dacapo = mx.get_env('DACAPO_CP') + if dacapo is None: + l = mx.library('DACAPO', False) + if l is not None: + dacapo = l.get_path(True) + else: + mx.abort('DaCapo 9.12 jar file must be specified with DACAPO_CP environment variable or as DACAPO library') + + if not isfile(dacapo) or not dacapo.endswith('.jar'): + mx.abort('Specified DaCapo jar file does not exist or is not a jar file: ' + dacapo) + + dacapoSuccess = re.compile(r"^===== DaCapo 9\.12 ([a-zA-Z0-9_]+) PASSED in ([0-9]+) msec =====", re.MULTILINE) + dacapoFail = re.compile(r"^===== DaCapo 9\.12 ([a-zA-Z0-9_]+) FAILED (warmup|) =====", re.MULTILINE) + dacapoTime = re.compile(r"===== DaCapo 9\.12 (?P[a-zA-Z0-9_]+) PASSED in (?P