diff --git a/doc/building.html b/doc/building.html index 11bac88d460..357b0f5fb4b 100644 --- a/doc/building.html +++ b/doc/building.html @@ -463,7 +463,7 @@ tar -xzf freetype-2.5.3.tar.gz
  • --with-native-debug-symbols=<method> - Specify if and how native debug symbols should be built. Available methods are none, internal, external, zipped. Default behavior depends on platform. See Native Debug Symbols for more details.
  • --with-version-string=<string> - Specify the version string this build will be identified with.
  • --with-version-<part>=<value> - A group of options, where <part> can be any of pre, opt, build, major, minor, security or patch. Use these options to modify just the corresponding part of the version string from the default, or the value provided by --with-version-string.
  • -
  • --with-jvm-variants=<variant>[,<variant>...] - Build the specified variant (or variants) of Hotspot. Valid variants are: server, client, minimal, core, zero, zeroshark, custom. Note that not all variants are possible to combine in a single build.
  • +
  • --with-jvm-variants=<variant>[,<variant>...] - Build the specified variant (or variants) of Hotspot. Valid variants are: server, client, minimal, core, zero, custom. Note that not all variants are possible to combine in a single build.
  • --with-jvm-features=<feature>[,<feature>...] - Use the specified JVM features when building Hotspot. The list of features will be enabled on top of the default list. For the custom JVM variant, this default list is empty. A complete list of available JVM features can be found using bash configure --help.
  • --with-target-bits=<bits> - Create a target binary suitable for running on a <bits> platform. Use this to create 32-bit output on a 64-bit build platform, instead of doing a full cross-compile. (This is known as a reduced build.)
  • diff --git a/doc/building.md b/doc/building.md index 75827aa2b17..878bdf29771 100644 --- a/doc/building.md +++ b/doc/building.md @@ -668,7 +668,7 @@ features, use `bash configure --help=short` instead.) from the default, or the value provided by `--with-version-string`. * `--with-jvm-variants=[,...]` - Build the specified variant (or variants) of Hotspot. Valid variants are: `server`, `client`, - `minimal`, `core`, `zero`, `zeroshark`, `custom`. Note that not all + `minimal`, `core`, `zero`, `custom`. Note that not all variants are possible to combine in a single build. * `--with-jvm-features=[,...]` - Use the specified JVM features when building Hotspot. The list of features will be enabled on top diff --git a/make/autoconf/flags.m4 b/make/autoconf/flags.m4 index 3e3770208e1..89bb736f2bf 100644 --- a/make/autoconf/flags.m4 +++ b/make/autoconf/flags.m4 @@ -1097,7 +1097,7 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER], ] ) fi - if ! HOTSPOT_CHECK_JVM_VARIANT(zero) && ! HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then + if ! HOTSPOT_CHECK_JVM_VARIANT(zero); then # Non-zero builds have stricter warnings $2JVM_CFLAGS="[$]$2JVM_CFLAGS -Wreturn-type -Wundef -Wformat=2" else diff --git a/make/autoconf/hotspot.m4 b/make/autoconf/hotspot.m4 index 487dbde68ac..3de1175c961 100644 --- a/make/autoconf/hotspot.m4 +++ b/make/autoconf/hotspot.m4 @@ -24,12 +24,12 @@ # # All valid JVM features, regardless of platform -VALID_JVM_FEATURES="compiler1 compiler2 zero shark minimal dtrace jvmti jvmci \ +VALID_JVM_FEATURES="compiler1 compiler2 zero minimal dtrace jvmti jvmci \ graal vm-structs jni-check services management all-gcs nmt cds \ static-build link-time-opt aot" # All valid JVM variants -VALID_JVM_VARIANTS="server client minimal core zero zeroshark custom" +VALID_JVM_VARIANTS="server client minimal core zero custom" ############################################################################### # Check if the specified JVM variant should be built. To be used in shell if @@ -62,13 +62,12 @@ AC_DEFUN([HOTSPOT_CHECK_JVM_FEATURE], # minimal: reduced form of client with optional features stripped out # core: normal interpreter only, no compiler # zero: C++ based interpreter only, no compiler -# zeroshark: C++ based interpreter, and a llvm-based compiler # custom: baseline JVM with no default features # AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_VARIANTS], [ AC_ARG_WITH([jvm-variants], [AS_HELP_STRING([--with-jvm-variants], - [JVM variants (separated by commas) to build (server,client,minimal,core,zero,zeroshark,custom) @<:@server@:>@])]) + [JVM variants (separated by commas) to build (server,client,minimal,core,zero,custom) @<:@server@:>@])]) SETUP_HOTSPOT_TARGET_CPU_PORT @@ -132,7 +131,7 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_VARIANTS], AC_SUBST(VALID_JVM_VARIANTS) AC_SUBST(JVM_VARIANT_MAIN) - if HOTSPOT_CHECK_JVM_VARIANT(zero) || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then + if HOTSPOT_CHECK_JVM_VARIANT(zero); then # zero behaves as a platform and rewrites these values. This is really weird. :( # We are guaranteed that we do not build any other variants when building zero. HOTSPOT_TARGET_CPU=zero @@ -325,15 +324,9 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES], fi fi - if ! HOTSPOT_CHECK_JVM_VARIANT(zero) && ! HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then + if ! HOTSPOT_CHECK_JVM_VARIANT(zero); then if HOTSPOT_CHECK_JVM_FEATURE(zero); then - AC_MSG_ERROR([To enable zero/zeroshark, you must use --with-jvm-variants=zero/zeroshark]) - fi - fi - - if ! HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then - if HOTSPOT_CHECK_JVM_FEATURE(shark); then - AC_MSG_ERROR([To enable shark, you must use --with-jvm-variants=zeroshark]) + AC_MSG_ERROR([To enable zero, you must use --with-jvm-variants=zero]) fi fi @@ -408,7 +401,6 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES], JVM_FEATURES_core="$NON_MINIMAL_FEATURES $JVM_FEATURES" JVM_FEATURES_minimal="compiler1 minimal $JVM_FEATURES $JVM_FEATURES_link_time_opt" JVM_FEATURES_zero="zero $NON_MINIMAL_FEATURES $JVM_FEATURES" - JVM_FEATURES_zeroshark="zero shark $NON_MINIMAL_FEATURES $JVM_FEATURES" JVM_FEATURES_custom="$JVM_FEATURES" AC_SUBST(JVM_FEATURES_server) @@ -416,7 +408,6 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES], AC_SUBST(JVM_FEATURES_core) AC_SUBST(JVM_FEATURES_minimal) AC_SUBST(JVM_FEATURES_zero) - AC_SUBST(JVM_FEATURES_zeroshark) AC_SUBST(JVM_FEATURES_custom) # Used for verification of Makefiles by check-jvm-feature @@ -437,7 +428,6 @@ AC_DEFUN_ONCE([HOTSPOT_VALIDATE_JVM_FEATURES], JVM_FEATURES_core="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_core | $SORT -u))" JVM_FEATURES_minimal="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_minimal | $SORT -u))" JVM_FEATURES_zero="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_zero | $SORT -u))" - JVM_FEATURES_zeroshark="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_zeroshark | $SORT -u))" JVM_FEATURES_custom="$($ECHO $($PRINTF '%s\n' $JVM_FEATURES_custom | $SORT -u))" # Validate features diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index fb4849e70b0..30215ee372a 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -232,7 +232,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS], # Should we build the serviceability agent (SA)? INCLUDE_SA=true - if HOTSPOT_CHECK_JVM_VARIANT(zero) || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then + if HOTSPOT_CHECK_JVM_VARIANT(zero); then INCLUDE_SA=false fi if test "x$OPENJDK_TARGET_OS" = xaix ; then diff --git a/make/autoconf/lib-std.m4 b/make/autoconf/lib-std.m4 index ceb8a45ca89..0b875bc7034 100644 --- a/make/autoconf/lib-std.m4 +++ b/make/autoconf/lib-std.m4 @@ -65,8 +65,7 @@ AC_DEFUN_ONCE([LIB_SETUP_STD_LIBS], # If dynamic was requested, it's available since it would fail above otherwise. # If dynamic wasn't requested, go with static unless it isn't available. AC_MSG_CHECKING([how to link with libstdc++]) - if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno \ - || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then + if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno ; then AC_MSG_RESULT([dynamic]) else LIBCXX="$LIBCXX $STATIC_STDCXX_FLAGS" diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4 index 98d202c589c..7d10ea4dd7f 100644 --- a/make/autoconf/libraries.m4 +++ b/make/autoconf/libraries.m4 @@ -79,7 +79,7 @@ AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES], fi # Check if ffi is needed - if HOTSPOT_CHECK_JVM_VARIANT(zero) || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then + if HOTSPOT_CHECK_JVM_VARIANT(zero); then NEEDS_LIB_FFI=true else NEEDS_LIB_FFI=false @@ -98,69 +98,11 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES], LIB_SETUP_FREETYPE LIB_SETUP_ALSA LIB_SETUP_LIBFFI - LIB_SETUP_LLVM LIB_SETUP_BUNDLED_LIBS LIB_SETUP_MISC_LIBS LIB_SETUP_SOLARIS_STLPORT ]) -################################################################################ -# Setup llvm (Low-Level VM) -################################################################################ -AC_DEFUN_ONCE([LIB_SETUP_LLVM], -[ - if HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then - AC_CHECK_PROG([LLVM_CONFIG], [llvm-config], [llvm-config]) - - if test "x$LLVM_CONFIG" != xllvm-config; then - AC_MSG_ERROR([llvm-config not found in $PATH.]) - fi - - llvm_components="jit mcjit engine nativecodegen native" - unset LLVM_CFLAGS - for flag in $("$LLVM_CONFIG" --cxxflags); do - if echo "${flag}" | grep -q '^-@<:@ID@:>@'; then - if test "${flag}" != "-D_DEBUG" ; then - if test "${LLVM_CFLAGS}" != "" ; then - LLVM_CFLAGS="${LLVM_CFLAGS} " - fi - LLVM_CFLAGS="${LLVM_CFLAGS}${flag}" - fi - fi - done - llvm_version=$("${LLVM_CONFIG}" --version | $SED 's/\.//; s/svn.*//') - LLVM_CFLAGS="${LLVM_CFLAGS} -DSHARK_LLVM_VERSION=${llvm_version}" - - unset LLVM_LDFLAGS - for flag in $("${LLVM_CONFIG}" --ldflags); do - if echo "${flag}" | grep -q '^-L'; then - if test "${LLVM_LDFLAGS}" != ""; then - LLVM_LDFLAGS="${LLVM_LDFLAGS} " - fi - LLVM_LDFLAGS="${LLVM_LDFLAGS}${flag}" - fi - done - - unset LLVM_LIBS - for flag in $("${LLVM_CONFIG}" --libs ${llvm_components}); do - if echo "${flag}" | grep -q '^-l'; then - if test "${LLVM_LIBS}" != ""; then - LLVM_LIBS="${LLVM_LIBS} " - fi - LLVM_LIBS="${LLVM_LIBS}${flag}" - fi - done - - # Due to https://llvm.org/bugs/show_bug.cgi?id=16902, llvm does not - # always properly detect -ltinfo - LLVM_LIBS="${LLVM_LIBS} -ltinfo" - - AC_SUBST(LLVM_CFLAGS) - AC_SUBST(LLVM_LDFLAGS) - AC_SUBST(LLVM_LIBS) - fi -]) - ################################################################################ # Setup various libraries, typically small system libraries ################################################################################ diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in index 06deccd8e31..ac590a32bce 100644 --- a/make/autoconf/spec.gmk.in +++ b/make/autoconf/spec.gmk.in @@ -219,7 +219,6 @@ JVM_FEATURES_client := @JVM_FEATURES_client@ JVM_FEATURES_core := @JVM_FEATURES_core@ JVM_FEATURES_minimal := @JVM_FEATURES_minimal@ JVM_FEATURES_zero := @JVM_FEATURES_zero@ -JVM_FEATURES_zeroshark := @JVM_FEATURES_zeroshark@ JVM_FEATURES_custom := @JVM_FEATURES_custom@ # Used for make-time verifications @@ -403,11 +402,6 @@ JVM_ASFLAGS := @JVM_ASFLAGS@ JVM_LIBS := @JVM_LIBS@ JVM_RCFLAGS := @JVM_RCFLAGS@ -# Flags for zeroshark -LLVM_CFLAGS := @LLVM_CFLAGS@ -LLVM_LIBS := @LLVM_LIBS@ -LLVM_LDFLAGS := @LLVM_LDFLAGS@ - # These flags might contain variables set by a custom extension that is included later. EXTRA_CFLAGS = @EXTRA_CFLAGS@ EXTRA_CXXFLAGS = @EXTRA_CXXFLAGS@ diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk index 04cafcd115c..cdbb01b0761 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -113,6 +113,7 @@ PLATFORM_MODULES += \ jdk.dynalink \ jdk.httpserver \ jdk.incubator.httpclient \ + jdk.internal.vm.compiler.management \ jdk.jsobject \ jdk.localedata \ jdk.naming.dns \ @@ -215,6 +216,7 @@ endif ifeq ($(INCLUDE_GRAAL), false) MODULES_FILTER += jdk.internal.vm.compiler + MODULES_FILTER += jdk.internal.vm.compiler.management endif ################################################################################ diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 1ef8a3beb3d..e5dd458f806 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -1060,7 +1060,7 @@ var getJibProfilesDependencies = function (input, common) { jtreg: { server: "javare", revision: "4.2", - build_number: "b08", + build_number: "b09", checksum_file: "MD5_VALUES", file: "jtreg_bin-4.2.zip", environment_name: "JT_HOME", diff --git a/make/copy/Copy-java.base.gmk b/make/copy/Copy-java.base.gmk index 7cbe140c25b..89d7d791c06 100644 --- a/make/copy/Copy-java.base.gmk +++ b/make/copy/Copy-java.base.gmk @@ -87,7 +87,7 @@ endif # # How to install jvm.cfg. # -ifeq ($(call check-jvm-variant, zero zeroshark), true) +ifeq ($(call check-jvm-variant, zero), true) JVMCFG_ARCH := zero else JVMCFG_ARCH := $(OPENJDK_TARGET_CPU_LEGACY) @@ -102,8 +102,6 @@ else endif JVMCFG := $(LIB_DST_DIR)/jvm.cfg -# To do: should this also support -zeroshark? - ifeq ($(OPENJDK_TARGET_CPU_BITS), 64) COPY_JVM_CFG_FILE := true else @@ -120,7 +118,7 @@ else COPY_JVM_CFG_FILE := true else # For zero, the default jvm.cfg file is sufficient - ifeq ($(call check-jvm-variant, zero zeroshark), true) + ifeq ($(call check-jvm-variant, zero), true) COPY_JVM_CFG_FILE := true endif endif diff --git a/make/gensrc/GensrcModuleLoaderMap.gmk b/make/gensrc/GensrcModuleLoaderMap.gmk index 5d4adeeccba..86d4446496a 100644 --- a/make/gensrc/GensrcModuleLoaderMap.gmk +++ b/make/gensrc/GensrcModuleLoaderMap.gmk @@ -54,15 +54,4 @@ $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/module/ModuleLoaderMap.java: GENSRC_JAVA_BASE += $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/module/ModuleLoaderMap.java -$(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat: \ - $(TOPDIR)/src/java.base/share/classes/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat \ - $(VARDEPS_FILE) $(BUILD_TOOLS_JDK) - $(MKDIR) -p $(@D) - $(RM) $@ $@.tmp - $(TOOL_GENCLASSLOADERMAP) -boot $(BOOT_MODULES_LIST) \ - -platform $(PLATFORM_MODULES_LIST) -o $@.tmp $< - $(MV) $@.tmp $@ - -GENSRC_JAVA_BASE += $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat - ################################################################################ diff --git a/make/hotspot/ide/CreateVSProject.gmk b/make/hotspot/ide/CreateVSProject.gmk index 1ba83b21a28..2040e3a1d37 100644 --- a/make/hotspot/ide/CreateVSProject.gmk +++ b/make/hotspot/ide/CreateVSProject.gmk @@ -75,7 +75,6 @@ ifeq ($(OPENJDK_TARGET_OS), windows) -ignorePath linux \ -ignorePath posix \ -ignorePath ppc \ - -ignorePath shark \ -ignorePath solaris \ -ignorePath sparc \ -ignorePath x86_32 \ diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index bf4280b8dea..5c7d7177420 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -58,6 +58,7 @@ JVM_CFLAGS_INCLUDES += \ -I$(JVM_VARIANT_OUTPUTDIR)/gensrc \ -I$(TOPDIR)/src/hotspot/share/precompiled \ -I$(TOPDIR)/src/hotspot/share/prims \ + -I$(TOPDIR)/src/java.base/share/native/include \ # # INCLUDE_SUFFIX_* is only meant for including the proper diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk index 9a69c5330bf..348e645d966 100644 --- a/make/hotspot/lib/JvmFeatures.gmk +++ b/make/hotspot/lib/JvmFeatures.gmk @@ -47,14 +47,9 @@ endif ifeq ($(call check-jvm-feature, zero), true) JVM_CFLAGS_FEATURES += -DZERO -DCC_INTERP -DZERO_LIBARCH='"$(OPENJDK_TARGET_CPU_LEGACY_LIB)"' $(LIBFFI_CFLAGS) JVM_LIBS_FEATURES += $(LIBFFI_LIBS) -endif - -ifeq ($(call check-jvm-feature, shark), true) - JVM_CFLAGS_FEATURES += -DSHARK $(LLVM_CFLAGS) - JVM_LDFLAGS_FEATURES += $(LLVM_LDFLAGS) - JVM_LIBS_FEATURES += $(LLVM_LIBS) -else - JVM_EXCLUDES += shark + ifeq ($(OPENJDK_TARGET_CPU), sparcv9) + BUILD_LIBJVM_EXTRA_FILES := $(TOPDIR)/src/hotspot/cpu/sparc/memset_with_concurrent_readers_sparc.cpp + endif endif ifeq ($(call check-jvm-feature, minimal), true) @@ -129,6 +124,7 @@ ifneq ($(call check-jvm-feature, all-gcs), true) cms/ g1/ parallel/ JVM_EXCLUDE_FILES += \ concurrentGCThread.cpp \ + suspendibleThreadSet.cpp \ plab.cpp JVM_EXCLUDE_FILES += \ g1MemoryPool.cpp \ diff --git a/make/jdk/src/classes/build/tools/module/GenModuleLoaderMap.java b/make/jdk/src/classes/build/tools/module/GenModuleLoaderMap.java index 6719277fac1..c6c90e0fb59 100644 --- a/make/jdk/src/classes/build/tools/module/GenModuleLoaderMap.java +++ b/make/jdk/src/classes/build/tools/module/GenModuleLoaderMap.java @@ -77,30 +77,22 @@ public class GenModuleLoaderMap { throw new IllegalArgumentException(source + " not exist"); } - boolean needsQuotes = outfile.toString().contains(".java.tmp"); - try (BufferedWriter bw = Files.newBufferedWriter(outfile, StandardCharsets.UTF_8); PrintWriter writer = new PrintWriter(bw)) { for (String line : Files.readAllLines(source)) { if (line.contains("@@BOOT_MODULE_NAMES@@")) { - line = patch(line, "@@BOOT_MODULE_NAMES@@", bootModules, needsQuotes); + line = patch(line, "@@BOOT_MODULE_NAMES@@", bootModules); } else if (line.contains("@@PLATFORM_MODULE_NAMES@@")) { - line = patch(line, "@@PLATFORM_MODULE_NAMES@@", platformModules, needsQuotes); + line = patch(line, "@@PLATFORM_MODULE_NAMES@@", platformModules); } writer.println(line); } } } - private static String patch(String s, String tag, Stream stream, boolean needsQuotes) { - String mns = null; - if (needsQuotes) { - mns = stream.sorted() - .collect(Collectors.joining("\",\n \"")); - } else { - mns = stream.sorted() - .collect(Collectors.joining("\n")); - } + private static String patch(String s, String tag, Stream stream) { + String mns = stream.sorted() + .collect(Collectors.joining("\",\n \"")); return s.replace(tag, mns); } diff --git a/make/lib/CoreLibraries.gmk b/make/lib/CoreLibraries.gmk index f8e0983a00d..090e425d703 100644 --- a/make/lib/CoreLibraries.gmk +++ b/make/lib/CoreLibraries.gmk @@ -300,7 +300,7 @@ LIBJLI_SRC_DIRS := $(call FindSrcDirsForLib, java.base, jli) LIBJLI_CFLAGS := $(CFLAGS_JDKLIB) -ifeq ($(call check-jvm-variant, zero zeroshark), true) +ifeq ($(call check-jvm-variant, zero), true) ERGO_FAMILY := zero else ifeq ($(OPENJDK_TARGET_CPU_ARCH), x86) diff --git a/make/test/JtregNativeHotspot.gmk b/make/test/JtregNativeHotspot.gmk index dfc45a7a86c..504c3b2d9b1 100644 --- a/make/test/JtregNativeHotspot.gmk +++ b/make/test/JtregNativeHotspot.gmk @@ -50,6 +50,7 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC += \ $(TOPDIR)/test/hotspot/jtreg/runtime/jni/8025979 \ $(TOPDIR)/test/hotspot/jtreg/runtime/jni/8033445 \ $(TOPDIR)/test/hotspot/jtreg/runtime/jni/checked \ + $(TOPDIR)/test/hotspot/jtreg/runtime/jni/FindClass \ $(TOPDIR)/test/hotspot/jtreg/runtime/jni/PrivateInterfaceMethods \ $(TOPDIR)/test/hotspot/jtreg/runtime/jni/ToStringInInterfaceTest \ $(TOPDIR)/test/hotspot/jtreg/runtime/jni/CalleeSavedRegisters \ @@ -59,6 +60,7 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC += \ $(TOPDIR)/test/hotspot/jtreg/runtime/SameObject \ $(TOPDIR)/test/hotspot/jtreg/runtime/BoolReturn \ $(TOPDIR)/test/hotspot/jtreg/runtime/noClassDefFoundMsg \ + $(TOPDIR)/test/hotspot/jtreg/runtime/RedefineTests \ $(TOPDIR)/test/hotspot/jtreg/compiler/floatingpoint/ \ $(TOPDIR)/test/hotspot/jtreg/compiler/calls \ $(TOPDIR)/test/hotspot/jtreg/serviceability/jvmti/GetOwnedMonitorInfo \ @@ -103,6 +105,7 @@ ifeq ($(TOOLCHAIN_TYPE), solstudio) BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMAAClassLoadPrepare := -lc BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMAAThreadStart := -lc BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libAllowedFunctions := -lc + BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libRedefineDoubleDelete := -lc endif ifeq ($(OPENJDK_TARGET_OS), linux) diff --git a/src/hotspot/.mx.jvmci/hotspot/templates/eclipse/cproject b/src/hotspot/.mx.jvmci/hotspot/templates/eclipse/cproject index b156340e98b..6f2353059e7 100644 --- a/src/hotspot/.mx.jvmci/hotspot/templates/eclipse/cproject +++ b/src/hotspot/.mx.jvmci/hotspot/templates/eclipse/cproject @@ -70,7 +70,7 @@ - + diff --git a/src/hotspot/.mx.jvmci/mx_jvmci.py b/src/hotspot/.mx.jvmci/mx_jvmci.py index 37a9baff97e..5b582b3d45d 100644 --- a/src/hotspot/.mx.jvmci/mx_jvmci.py +++ b/src/hotspot/.mx.jvmci/mx_jvmci.py @@ -256,14 +256,10 @@ class HotSpotProject(mx.NativeProject): """ roots = [ - 'ASSEMBLY_EXCEPTION', - 'LICENSE', - 'README', - 'THIRD_PARTY_README', - 'agent', - 'make', - 'src', - 'test' + 'cpu', + 'os', + 'os_cpu', + 'share' ] for jvmVariant in _jdkJvmVariants: @@ -605,6 +601,16 @@ def _get_openjdk_cpu(): def _get_openjdk_os_cpu(): return _get_openjdk_os() + '-' + _get_openjdk_cpu() +def _get_jdk_dir(): + suiteParentDir = dirname(_suite.dir) + # suitParentDir is now something like: /some_prefix/jdk10-hs/open/src + pathComponents = suiteParentDir.split(os.sep) + for i in range(0, len(pathComponents)): + if pathComponents[i] in ["open", "src"]: + del pathComponents[i:] + break + return os.path.join(os.sep, *pathComponents) + def _get_jdk_build_dir(debugLevel=None): """ Gets the directory into which the JDK is built. This directory contains @@ -613,7 +619,7 @@ def _get_jdk_build_dir(debugLevel=None): if debugLevel is None: debugLevel = _vm.debugLevel name = '{}-{}-{}-{}'.format(_get_openjdk_os_cpu(), 'normal', _vm.jvmVariant, debugLevel) - return join(dirname(_suite.dir), 'build', name) + return join(_get_jdk_dir(), 'build', name) _jvmci_bootclasspath_prepends = [] diff --git a/src/hotspot/.mx.jvmci/suite.py b/src/hotspot/.mx.jvmci/suite.py index 9415623d92b..edea9f2d82e 100644 --- a/src/hotspot/.mx.jvmci/suite.py +++ b/src/hotspot/.mx.jvmci/suite.py @@ -24,9 +24,7 @@ suite = { "defaultLicense" : "GPLv2-CPE", - # This puts mx/ as a sibling of the JDK build configuration directories - # (e.g., macosx-x86_64-normal-server-release). - "outputRoot" : "../build/mx/hotspot", + "outputRoot" : "../../build/mx/hotspot", # ------------- Libraries ------------- @@ -43,7 +41,7 @@ suite = { # ------------- JVMCI:Service ------------- "jdk.vm.ci.services" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], "javaCompliance" : "9", "workingSets" : "API,JVMCI", @@ -52,7 +50,7 @@ suite = { # ------------- JVMCI:API ------------- "jdk.vm.ci.common" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], "checkstyle" : "jdk.vm.ci.services", "javaCompliance" : "9", @@ -60,7 +58,7 @@ suite = { }, "jdk.vm.ci.meta" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], "checkstyle" : "jdk.vm.ci.services", "javaCompliance" : "9", @@ -68,7 +66,7 @@ suite = { }, "jdk.vm.ci.code" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], "dependencies" : ["jdk.vm.ci.meta"], "checkstyle" : "jdk.vm.ci.services", @@ -77,7 +75,7 @@ suite = { }, "jdk.vm.ci.code.test" : { - "subDir" : "test/compiler/jvmci", + "subDir" : "../../test/hotspot/jtreg/compiler/jvmci", "sourceDirs" : ["src"], "dependencies" : [ "mx:JUNIT", @@ -92,7 +90,7 @@ suite = { }, "jdk.vm.ci.runtime" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], "dependencies" : [ "jdk.vm.ci.code", @@ -104,7 +102,7 @@ suite = { }, "jdk.vm.ci.runtime.test" : { - "subDir" : "test/compiler/jvmci", + "subDir" : "../../test/hotspot/jtreg/compiler/jvmci", "sourceDirs" : ["src"], "dependencies" : [ "mx:JUNIT", @@ -119,7 +117,7 @@ suite = { # ------------- JVMCI:HotSpot ------------- "jdk.vm.ci.aarch64" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], "dependencies" : ["jdk.vm.ci.code"], "checkstyle" : "jdk.vm.ci.services", @@ -128,7 +126,7 @@ suite = { }, "jdk.vm.ci.amd64" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], "dependencies" : ["jdk.vm.ci.code"], "checkstyle" : "jdk.vm.ci.services", @@ -137,7 +135,7 @@ suite = { }, "jdk.vm.ci.sparc" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], "dependencies" : ["jdk.vm.ci.code"], "checkstyle" : "jdk.vm.ci.services", @@ -146,7 +144,7 @@ suite = { }, "jdk.vm.ci.hotspot" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], "dependencies" : [ "jdk.vm.ci.common", @@ -163,7 +161,7 @@ suite = { }, "jdk.vm.ci.hotspot.test" : { - "subDir" : "test/compiler/jvmci", + "subDir" : "../../test/hotspot/jtreg/compiler/jvmci", "sourceDirs" : ["src"], "dependencies" : [ "TESTNG", @@ -175,7 +173,7 @@ suite = { }, "jdk.vm.ci.hotspot.aarch64" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], "dependencies" : [ "jdk.vm.ci.aarch64", @@ -187,7 +185,7 @@ suite = { }, "jdk.vm.ci.hotspot.amd64" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], "dependencies" : [ "jdk.vm.ci.amd64", @@ -199,7 +197,7 @@ suite = { }, "jdk.vm.ci.hotspot.sparc" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], "dependencies" : [ "jdk.vm.ci.sparc", @@ -221,12 +219,12 @@ suite = { # ------------- Distributions ------------- "JVMCI_SERVICES" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "dependencies" : ["jdk.vm.ci.services"], }, "JVMCI_API" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "dependencies" : [ "jdk.vm.ci.runtime", "jdk.vm.ci.common", @@ -240,7 +238,7 @@ suite = { }, "JVMCI_HOTSPOT" : { - "subDir" : "src/jdk.internal.vm.ci/share/classes", + "subDir" : "../jdk.internal.vm.ci/share/classes", "dependencies" : [ "jdk.vm.ci.hotspot.aarch64", "jdk.vm.ci.hotspot.amd64", @@ -253,7 +251,7 @@ suite = { }, "JVMCI_TEST" : { - "subDir" : "test/compiler/jvmci", + "subDir" : "../../test/hotspot/jtreg/compiler/jvmci", "dependencies" : [ "jdk.vm.ci.runtime.test", ], diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index e6d9de99685..b7ff274e212 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -2575,13 +2575,9 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { Register mdo = op->mdo()->as_register(); __ mov_metadata(mdo, md->constant_encoding()); Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); - Bytecodes::Code bc = method->java_code_at_bci(bci); - const bool callee_is_static = callee->is_loaded() && callee->is_static(); // Perform additional virtual call profiling for invokevirtual and // invokeinterface bytecodes - if ((bc == Bytecodes::_invokevirtual || bc == Bytecodes::_invokeinterface) && - !callee_is_static && // required for optimized MH invokes - C1ProfileVirtualCalls) { + if (op->should_profile_receiver_type()) { assert(op->recv()->is_single_cpu(), "recv must be allocated"); Register recv = op->recv()->as_register(); assert_different_registers(mdo, recv); diff --git a/src/hotspot/cpu/aarch64/jniTypes_aarch64.hpp b/src/hotspot/cpu/aarch64/jniTypes_aarch64.hpp index 857a45a6071..bdf4d55bfbc 100644 --- a/src/hotspot/cpu/aarch64/jniTypes_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/jniTypes_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,9 +26,9 @@ #ifndef CPU_AARCH64_VM_JNITYPES_AARCH64_HPP #define CPU_AARCH64_VM_JNITYPES_AARCH64_HPP +#include "jni.h" #include "memory/allocation.hpp" #include "oops/oop.hpp" -#include "prims/jni.h" // This file holds platform-dependent routines used to write primitive jni // types to the array of arguments passed into JavaCalls::call diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 78637f21dc1..a7fb3df4ee7 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -2840,6 +2840,44 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi bind(L_done); } +// Code for BigInteger::mulAdd instrinsic +// out = r0 +// in = r1 +// offset = r2 (already out.length-offset) +// len = r3 +// k = r4 +// +// pseudo code from java implementation: +// carry = 0; +// offset = out.length-offset - 1; +// for (int j=len-1; j >= 0; j--) { +// product = (in[j] & LONG_MASK) * kLong + (out[offset] & LONG_MASK) + carry; +// out[offset--] = (int)product; +// carry = product >>> 32; +// } +// return (int)carry; +void MacroAssembler::mul_add(Register out, Register in, Register offset, + Register len, Register k) { + Label LOOP, END; + // pre-loop + cmp(len, zr); // cmp, not cbz/cbnz: to use condition twice => less branches + csel(out, zr, out, Assembler::EQ); + br(Assembler::EQ, END); + add(in, in, len, LSL, 2); // in[j+1] address + add(offset, out, offset, LSL, 2); // out[offset + 1] address + mov(out, zr); // used to keep carry now + BIND(LOOP); + ldrw(rscratch1, Address(pre(in, -4))); + madd(rscratch1, rscratch1, k, out); + ldrw(rscratch2, Address(pre(offset, -4))); + add(rscratch1, rscratch1, rscratch2); + strw(rscratch1, Address(offset)); + lsr(out, rscratch1, 32); + subs(len, len, 1); + br(Assembler::NE, LOOP); + BIND(END); +} + /** * Emits code to update CRC-32 with a byte value according to constants in table * @@ -3291,6 +3329,7 @@ void MacroAssembler::load_mirror(Register dst, Register method) { ldr(dst, Address(dst, ConstMethod::constants_offset())); ldr(dst, Address(dst, ConstantPool::pool_holder_offset_in_bytes())); ldr(dst, Address(dst, mirror_offset)); + resolve_oop_handle(dst); } void MacroAssembler::cmp_klass(Register oop, Register trial_klass, Register tmp) { diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index a3a3c74c626..d0ca968bd44 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1265,6 +1265,7 @@ public: void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6, Register tmp7); + void mul_add(Register out, Register in, Register offs, Register len, Register k); // ISB may be needed because of a safepoint void maybe_isb() { isb(); } diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index e6e79a468d2..d9c2cdc4a52 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -3607,6 +3607,63 @@ class StubGenerator: public StubCodeGenerator { return start; } + address generate_squareToLen() { + // squareToLen algorithm for sizes 1..127 described in java code works + // faster than multiply_to_len on some CPUs and slower on others, but + // multiply_to_len shows a bit better overall results + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "squareToLen"); + address start = __ pc(); + + const Register x = r0; + const Register xlen = r1; + const Register z = r2; + const Register zlen = r3; + const Register y = r4; // == x + const Register ylen = r5; // == xlen + + const Register tmp1 = r10; + const Register tmp2 = r11; + const Register tmp3 = r12; + const Register tmp4 = r13; + const Register tmp5 = r14; + const Register tmp6 = r15; + const Register tmp7 = r16; + + RegSet spilled_regs = RegSet::of(y, ylen); + BLOCK_COMMENT("Entry:"); + __ enter(); + __ push(spilled_regs, sp); + __ mov(y, x); + __ mov(ylen, xlen); + __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7); + __ pop(spilled_regs, sp); + __ leave(); + __ ret(lr); + return start; + } + + address generate_mulAdd() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "mulAdd"); + + address start = __ pc(); + + const Register out = r0; + const Register in = r1; + const Register offset = r2; + const Register len = r3; + const Register k = r4; + + BLOCK_COMMENT("Entry:"); + __ enter(); + __ mul_add(out, in, offset, len, k); + __ leave(); + __ ret(lr); + + return start; + } + void ghash_multiply(FloatRegister result_lo, FloatRegister result_hi, FloatRegister a, FloatRegister b, FloatRegister a1_xor_a0, FloatRegister tmp1, FloatRegister tmp2, FloatRegister tmp3, FloatRegister tmp4) { @@ -4913,6 +4970,14 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_multiplyToLen = generate_multiplyToLen(); } + if (UseSquareToLenIntrinsic) { + StubRoutines::_squareToLen = generate_squareToLen(); + } + + if (UseMulAddIntrinsic) { + StubRoutines::_mulAdd = generate_mulAdd(); + } + if (UseMontgomeryMultiplyIntrinsic) { StubCodeMark mark(this, "StubRoutines", "montgomeryMultiply"); MontgomeryMultiplyGenerator g(_masm, /*squaring*/false); diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp index ae182677be5..11b3f49292c 100644 --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp @@ -2195,6 +2195,13 @@ void TemplateTable::_return(TosState state) __ bind(skip_register_finalizer); } + // Explicitly reset last_sp, for handling special case in TemplateInterpreter::deopt_reexecute_entry +#ifdef ASSERT + if (state == vtos) { + __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); + } +#endif + // Issue a StoreStore barrier after all stores but before return // from any constructor for any class with a final field. We don't // know if this is a finalizer, so we always do so. @@ -2297,6 +2304,7 @@ void TemplateTable::load_field_cp_cache_entry(Register obj, ConstantPoolCacheEntry::f1_offset()))); const int mirror_offset = in_bytes(Klass::java_mirror_offset()); __ ldr(obj, Address(obj, mirror_offset)); + __ resolve_oop_handle(obj); } } diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 722ebbba322..8480e4e8e71 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -340,6 +340,14 @@ void VM_Version::get_processor_features() { UseMultiplyToLenIntrinsic = true; } + if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) { + UseSquareToLenIntrinsic = true; + } + + if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) { + UseMulAddIntrinsic = true; + } + if (FLAG_IS_DEFAULT(UseBarriersForVolatile)) { UseBarriersForVolatile = (_features & CPU_DMB_ATOMICS) != 0; } diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index caf00718656..3f1692f7544 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -3168,14 +3168,9 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { } Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias); - Bytecodes::Code bc = method->java_code_at_bci(bci); - const bool callee_is_static = callee->is_loaded() && callee->is_static(); // Perform additional virtual call profiling for invokevirtual and // invokeinterface bytecodes - if ((bc == Bytecodes::_invokevirtual || bc == Bytecodes::_invokeinterface) && - !callee_is_static && // required for optimized MH invokes - C1ProfileVirtualCalls) { - + if (op->should_profile_receiver_type()) { assert(op->recv()->is_single_cpu(), "recv must be allocated"); Register recv = op->recv()->as_register(); assert_different_registers(mdo, tmp1, recv); diff --git a/src/hotspot/cpu/arm/jniTypes_arm.hpp b/src/hotspot/cpu/arm/jniTypes_arm.hpp index 7b23ccfe262..636f8e81a2c 100644 --- a/src/hotspot/cpu/arm/jniTypes_arm.hpp +++ b/src/hotspot/cpu/arm/jniTypes_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2017, 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 @@ -25,9 +25,9 @@ #ifndef CPU_ARM_VM_JNITYPES_ARM_HPP #define CPU_ARM_VM_JNITYPES_ARM_HPP +#include "jni.h" #include "memory/allocation.hpp" #include "oops/oop.hpp" -#include "prims/jni.h" // This file holds platform-dependent routines used to write primitive jni // types to the array of arguments passed into JavaCalls::call diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp index 53eb53f2c7f..ea4d7782983 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp @@ -2899,6 +2899,7 @@ void MacroAssembler::load_mirror(Register mirror, Register method, Register tmp) ldr(tmp, Address(tmp, ConstMethod::constants_offset())); ldr(tmp, Address(tmp, ConstantPool::pool_holder_offset_in_bytes())); ldr(mirror, Address(tmp, mirror_offset)); + resolve_oop_handle(mirror); } diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 59bc2e5b5d8..666cbd8860e 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -42,10 +42,6 @@ #ifdef COMPILER2 #include "opto/runtime.hpp" #endif -#ifdef SHARK -#include "compiler/compileBroker.hpp" -#include "shark/sharkCompiler.hpp" -#endif #define __ masm-> diff --git a/src/hotspot/cpu/arm/stubGenerator_arm.cpp b/src/hotspot/cpu/arm/stubGenerator_arm.cpp index d5ca6401fa4..97ef93c2e4f 100644 --- a/src/hotspot/cpu/arm/stubGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/stubGenerator_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2017, 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 @@ -2867,46 +2867,51 @@ class StubGenerator: public StubCodeGenerator { // Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR) except for callee_saved_regs. void gen_write_ref_array_pre_barrier(Register addr, Register count, int callee_saved_regs) { BarrierSet* bs = Universe::heap()->barrier_set(); - if (bs->has_write_ref_pre_barrier()) { - assert(bs->has_write_ref_array_pre_opt(), - "Else unsupported barrier set."); + switch (bs->kind()) { + case BarrierSet::G1SATBCTLogging: + { + assert( addr->encoding() < callee_saved_regs, "addr must be saved"); + assert(count->encoding() < callee_saved_regs, "count must be saved"); - assert( addr->encoding() < callee_saved_regs, "addr must be saved"); - assert(count->encoding() < callee_saved_regs, "count must be saved"); - - BLOCK_COMMENT("PreBarrier"); + BLOCK_COMMENT("PreBarrier"); #ifdef AARCH64 - callee_saved_regs = align_up(callee_saved_regs, 2); - for (int i = 0; i < callee_saved_regs; i += 2) { - __ raw_push(as_Register(i), as_Register(i+1)); - } + callee_saved_regs = align_up(callee_saved_regs, 2); + for (int i = 0; i < callee_saved_regs; i += 2) { + __ raw_push(as_Register(i), as_Register(i+1)); + } #else - RegisterSet saved_regs = RegisterSet(R0, as_Register(callee_saved_regs-1)); - __ push(saved_regs | R9ifScratched); + RegisterSet saved_regs = RegisterSet(R0, as_Register(callee_saved_regs-1)); + __ push(saved_regs | R9ifScratched); #endif // AARCH64 - if (addr != R0) { - assert_different_registers(count, R0); - __ mov(R0, addr); - } + if (addr != R0) { + assert_different_registers(count, R0); + __ mov(R0, addr); + } #ifdef AARCH64 - __ zero_extend(R1, count, 32); // BarrierSet::static_write_ref_array_pre takes size_t + __ zero_extend(R1, count, 32); // BarrierSet::static_write_ref_array_pre takes size_t #else - if (count != R1) { - __ mov(R1, count); - } + if (count != R1) { + __ mov(R1, count); + } #endif // AARCH64 - __ call(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre)); + __ call(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre)); #ifdef AARCH64 - for (int i = callee_saved_regs - 2; i >= 0; i -= 2) { - __ raw_pop(as_Register(i), as_Register(i+1)); - } + for (int i = callee_saved_regs - 2; i >= 0; i -= 2) { + __ raw_pop(as_Register(i), as_Register(i+1)); + } #else - __ pop(saved_regs | R9ifScratched); + __ pop(saved_regs | R9ifScratched); #endif // AARCH64 + } + case BarrierSet::CardTableForRS: + case BarrierSet::CardTableExtension: + break; + default: + ShouldNotReachHere(); } } #endif // INCLUDE_ALL_GCS diff --git a/src/hotspot/cpu/arm/templateTable_arm.cpp b/src/hotspot/cpu/arm/templateTable_arm.cpp index 7fd60ce8d2d..93018d26820 100644 --- a/src/hotspot/cpu/arm/templateTable_arm.cpp +++ b/src/hotspot/cpu/arm/templateTable_arm.cpp @@ -2844,6 +2844,19 @@ void TemplateTable::_return(TosState state) { __ bind(skip_register_finalizer); } + // Explicitly reset last_sp, for handling special case in TemplateInterpreter::deopt_reexecute_entry +#ifdef ASSERT + if (state == vtos) { +#ifndef AARCH64 + __ mov(Rtemp, 0); + __ str(Rtemp, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize)); +#else + __ restore_sp_after_call(Rtemp); + __ restore_stack_top(); +#endif + } +#endif + // Narrow result if state is itos but result type is smaller. // Need to narrow in the return bytecode rather than in generate_return_entry // since compiled code callers expect the result to already be narrowed. @@ -2963,6 +2976,7 @@ void TemplateTable::load_field_cp_cache_entry(Register Rcache, cp_base_offset + ConstantPoolCacheEntry::f1_offset())); const int mirror_offset = in_bytes(Klass::java_mirror_offset()); __ ldr(Robj, Address(Robj, mirror_offset)); + __ resolve_oop_handle(Robj); } } diff --git a/src/hotspot/cpu/ppc/assembler_ppc.hpp b/src/hotspot/cpu/ppc/assembler_ppc.hpp index 26b77b8cbc3..03be7f4bdcb 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp @@ -517,6 +517,9 @@ class Assembler : public AbstractAssembler { XXPERMDI_OPCODE= (60u << OPCODE_SHIFT | 10u << 3), XXMRGHW_OPCODE = (60u << OPCODE_SHIFT | 18u << 3), XXMRGLW_OPCODE = (60u << OPCODE_SHIFT | 50u << 3), + XXSPLTW_OPCODE = (60u << OPCODE_SHIFT | 164u << 2), + XXLXOR_OPCODE = (60u << OPCODE_SHIFT | 154u << 3), + XXLEQV_OPCODE = (60u << OPCODE_SHIFT | 186u << 3), // Vector Permute and Formatting VPKPX_OPCODE = (4u << OPCODE_SHIFT | 782u ), @@ -1125,6 +1128,7 @@ class Assembler : public AbstractAssembler { static int vsplti_sim(int x) { return opp_u_field(x, 15, 11); } // for vsplti* instructions static int vsldoi_shb(int x) { return opp_u_field(x, 25, 22); } // for vsldoi instruction static int vcmp_rc( int x) { return opp_u_field(x, 21, 21); } // for vcmp* instructions + static int xxsplt_uim(int x) { return opp_u_field(x, 15, 14); } // for xxsplt* instructions //static int xo1( int x) { return opp_u_field(x, 29, 21); }// is contained in our opcodes //static int xo2( int x) { return opp_u_field(x, 30, 21); }// is contained in our opcodes @@ -1308,6 +1312,7 @@ class Assembler : public AbstractAssembler { inline void li( Register d, int si16); inline void lis( Register d, int si16); inline void addir(Register d, int si16, Register a); + inline void subi( Register d, Register a, int si16); static bool is_addi(int x) { return ADDI_OPCODE == (x & ADDI_OPCODE_MASK); @@ -2154,6 +2159,11 @@ class Assembler : public AbstractAssembler { inline void xxpermdi( VectorSRegister d, VectorSRegister a, VectorSRegister b, int dm); inline void xxmrghw( VectorSRegister d, VectorSRegister a, VectorSRegister b); inline void xxmrglw( VectorSRegister d, VectorSRegister a, VectorSRegister b); + inline void mtvsrd( VectorSRegister d, Register a); + inline void mtvsrwz( VectorSRegister d, Register a); + inline void xxspltw( VectorSRegister d, VectorSRegister b, int ui2); + inline void xxlxor( VectorSRegister d, VectorSRegister a, VectorSRegister b); + inline void xxleqv( VectorSRegister d, VectorSRegister a, VectorSRegister b); // VSX Extended Mnemonics inline void xxspltd( VectorSRegister d, VectorSRegister a, int x); @@ -2174,7 +2184,8 @@ class Assembler : public AbstractAssembler { inline void vsbox( VectorRegister d, VectorRegister a); // SHA (introduced with Power 8) - // Not yet implemented. + inline void vshasigmad(VectorRegister d, VectorRegister a, bool st, int six); + inline void vshasigmaw(VectorRegister d, VectorRegister a, bool st, int six); // Vector Binary Polynomial Multiplication (introduced with Power 8) inline void vpmsumb( VectorRegister d, VectorRegister a, VectorRegister b); @@ -2285,6 +2296,11 @@ class Assembler : public AbstractAssembler { inline void lvsl( VectorRegister d, Register s2); inline void lvsr( VectorRegister d, Register s2); + // Endianess specific concatenation of 2 loaded vectors. + inline void load_perm(VectorRegister perm, Register addr); + inline void vec_perm(VectorRegister first_dest, VectorRegister second, VectorRegister perm); + inline void vec_perm(VectorRegister dest, VectorRegister first, VectorRegister second, VectorRegister perm); + // RegisterOrConstant versions. // These emitters choose between the versions using two registers and // those with register and immediate, depending on the content of roc. diff --git a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp index d21ffaf8fcb..3931b56093e 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp @@ -164,6 +164,7 @@ inline void Assembler::divwo_( Register d, Register a, Register b) { emit_int32 inline void Assembler::li( Register d, int si16) { Assembler::addi_r0ok( d, R0, si16); } inline void Assembler::lis( Register d, int si16) { Assembler::addis_r0ok(d, R0, si16); } inline void Assembler::addir(Register d, int si16, Register a) { Assembler::addi(d, a, si16); } +inline void Assembler::subi( Register d, Register a, int si16) { Assembler::addi(d, a, -si16); } // PPC 1, section 3.3.9, Fixed-Point Compare Instructions inline void Assembler::cmpi( ConditionRegister f, int l, Register a, int si16) { emit_int32( CMPI_OPCODE | bf(f) | l10(l) | ra(a) | simm(si16,16)); } @@ -760,9 +761,14 @@ inline void Assembler::lvsr( VectorRegister d, Register s1, Register s2) { emit // Vector-Scalar (VSX) instructions. inline void Assembler::lxvd2x( VectorSRegister d, Register s1) { emit_int32( LXVD2X_OPCODE | vsrt(d) | ra(0) | rb(s1)); } inline void Assembler::lxvd2x( VectorSRegister d, Register s1, Register s2) { emit_int32( LXVD2X_OPCODE | vsrt(d) | ra0mem(s1) | rb(s2)); } -inline void Assembler::stxvd2x( VectorSRegister d, Register s1) { emit_int32( STXVD2X_OPCODE | vsrt(d) | ra(0) | rb(s1)); } -inline void Assembler::stxvd2x( VectorSRegister d, Register s1, Register s2) { emit_int32( STXVD2X_OPCODE | vsrt(d) | ra0mem(s1) | rb(s2)); } -inline void Assembler::mtvrd( VectorRegister d, Register a) { emit_int32( MTVSRD_OPCODE | vsrt(d->to_vsr()) | ra(a)); } +inline void Assembler::stxvd2x( VectorSRegister d, Register s1) { emit_int32( STXVD2X_OPCODE | vsrs(d) | ra(0) | rb(s1)); } +inline void Assembler::stxvd2x( VectorSRegister d, Register s1, Register s2) { emit_int32( STXVD2X_OPCODE | vsrs(d) | ra0mem(s1) | rb(s2)); } +inline void Assembler::mtvsrd( VectorSRegister d, Register a) { emit_int32( MTVSRD_OPCODE | vsrt(d) | ra(a)); } +inline void Assembler::mtvsrwz( VectorSRegister d, Register a) { emit_int32( MTVSRWZ_OPCODE | vsrt(d) | ra(a)); } +inline void Assembler::xxspltw( VectorSRegister d, VectorSRegister b, int ui2) { emit_int32( XXSPLTW_OPCODE | vsrt(d) | vsrb(b) | xxsplt_uim(uimm(ui2,2))); } +inline void Assembler::xxlxor( VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XXLXOR_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); } +inline void Assembler::xxleqv( VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XXLEQV_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); } +inline void Assembler::mtvrd( VectorRegister d, Register a) { emit_int32( MTVSRD_OPCODE | vsrt(d->to_vsr()) | ra(a)); } inline void Assembler::mfvrd( Register a, VectorRegister d) { emit_int32( MFVSRD_OPCODE | vsrt(d->to_vsr()) | ra(a)); } inline void Assembler::mtvrwz( VectorRegister d, Register a) { emit_int32( MTVSRWZ_OPCODE | vsrt(d->to_vsr()) | ra(a)); } inline void Assembler::mfvrwz( Register a, VectorRegister d) { emit_int32( MFVSRWZ_OPCODE | vsrt(d->to_vsr()) | ra(a)); } @@ -925,7 +931,8 @@ inline void Assembler::vncipherlast(VectorRegister d, VectorRegister a, VectorRe inline void Assembler::vsbox( VectorRegister d, VectorRegister a) { emit_int32( VSBOX_OPCODE | vrt(d) | vra(a) ); } // SHA (introduced with Power 8) -// Not yet implemented. +inline void Assembler::vshasigmad(VectorRegister d, VectorRegister a, bool st, int six) { emit_int32( VSHASIGMAD_OPCODE | vrt(d) | vra(a) | vst(st) | vsix(six)); } +inline void Assembler::vshasigmaw(VectorRegister d, VectorRegister a, bool st, int six) { emit_int32( VSHASIGMAW_OPCODE | vrt(d) | vra(a) | vst(st) | vsix(six)); } // Vector Binary Polynomial Multiplication (introduced with Power 8) inline void Assembler::vpmsumb( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VPMSUMB_OPCODE | vrt(d) | vra(a) | vrb(b)); } @@ -1034,6 +1041,30 @@ inline void Assembler::stvxl( VectorRegister d, Register s2) { emit_int32( STVXL inline void Assembler::lvsl( VectorRegister d, Register s2) { emit_int32( LVSL_OPCODE | vrt(d) | rb(s2)); } inline void Assembler::lvsr( VectorRegister d, Register s2) { emit_int32( LVSR_OPCODE | vrt(d) | rb(s2)); } +inline void Assembler::load_perm(VectorRegister perm, Register addr) { +#if defined(VM_LITTLE_ENDIAN) + lvsr(perm, addr); +#else + lvsl(perm, addr); +#endif +} + +inline void Assembler::vec_perm(VectorRegister first_dest, VectorRegister second, VectorRegister perm) { +#if defined(VM_LITTLE_ENDIAN) + vperm(first_dest, second, first_dest, perm); +#else + vperm(first_dest, first_dest, second, perm); +#endif +} + +inline void Assembler::vec_perm(VectorRegister dest, VectorRegister first, VectorRegister second, VectorRegister perm) { +#if defined(VM_LITTLE_ENDIAN) + vperm(dest, second, first, perm); +#else + vperm(dest, first, second, perm); +#endif +} + inline void Assembler::load_const(Register d, void* x, Register tmp) { load_const(d, (long)x, tmp); } diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 62be4f4820b..58a5df65c09 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -2774,13 +2774,9 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); } - Bytecodes::Code bc = method->java_code_at_bci(bci); - const bool callee_is_static = callee->is_loaded() && callee->is_static(); // Perform additional virtual call profiling for invokevirtual and - // invokeinterface bytecodes. - if ((bc == Bytecodes::_invokevirtual || bc == Bytecodes::_invokeinterface) && - !callee_is_static && // Required for optimized MH invokes. - C1ProfileVirtualCalls) { + // invokeinterface bytecodes + if (op->should_profile_receiver_type()) { assert(op->recv()->is_single_cpu(), "recv must be allocated"); Register recv = op->recv()->as_register(); assert_different_registers(mdo, tmp1, recv); diff --git a/src/hotspot/cpu/ppc/globals_ppc.hpp b/src/hotspot/cpu/ppc/globals_ppc.hpp index 0bc041e9188..b6d04455c84 100644 --- a/src/hotspot/cpu/ppc/globals_ppc.hpp +++ b/src/hotspot/cpu/ppc/globals_ppc.hpp @@ -32,7 +32,7 @@ // Sets the default values for platform dependent flags used by the runtime system. // (see globals.hpp) -define_pd_global(bool, ShareVtableStubs, false); // Improves performance markedly for mtrt and compress. +define_pd_global(bool, ShareVtableStubs, true); define_pd_global(bool, NeedsDeoptSuspend, false); // Only register window machines need this. @@ -103,6 +103,9 @@ define_pd_global(intx, InitArrayShortSize, 9*BytesPerLong); "CPU Version: x for PowerX. Currently recognizes Power5 to " \ "Power8. Default is 0. Newer CPUs will be recognized as Power8.") \ \ + product(bool, SuperwordUseVSX, false, \ + "Use Power8 VSX instructions for superword optimization.") \ + \ /* Reoptimize code-sequences of calls at runtime, e.g. replace an */ \ /* indirect call by a direct call. */ \ product(bool, ReoptimizeCallSequences, true, \ diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index 0db86269875..668fe93a7fa 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -863,7 +863,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // // markOop displaced_header = obj->mark().set_unlocked(); // monitor->lock()->set_displaced_header(displaced_header); - // if (Atomic::cmpxchg_ptr(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) { + // if (Atomic::cmpxchg(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) { // // We stored the monitor address into the object's mark word. // } else if (THREAD->is_lock_owned((address)displaced_header)) // // Simple recursive case. @@ -901,7 +901,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { std(displaced_header, BasicObjectLock::lock_offset_in_bytes() + BasicLock::displaced_header_offset_in_bytes(), monitor); - // if (Atomic::cmpxchg_ptr(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) { + // if (Atomic::cmpxchg(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) { // Store stack address of the BasicObjectLock (this is monitor) into object. addi(object_mark_addr, object, oopDesc::mark_offset_in_bytes()); @@ -977,7 +977,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_e // if ((displaced_header = monitor->displaced_header()) == NULL) { // // Recursive unlock. Mark the monitor unlocked by setting the object field to NULL. // monitor->set_obj(NULL); - // } else if (Atomic::cmpxchg_ptr(displaced_header, obj->mark_addr(), monitor) == monitor) { + // } else if (Atomic::cmpxchg(displaced_header, obj->mark_addr(), monitor) == monitor) { // // We swapped the unlocked mark in displaced_header into the object's mark word. // monitor->set_obj(NULL); // } else { @@ -1010,7 +1010,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_e cmpdi(CCR0, displaced_header, 0); beq(CCR0, free_slot); // recursive unlock - // } else if (Atomic::cmpxchg_ptr(displaced_header, obj->mark_addr(), monitor) == monitor) { + // } else if (Atomic::cmpxchg(displaced_header, obj->mark_addr(), monitor) == monitor) { // // We swapped the unlocked mark in displaced_header into the object's mark word. // monitor->set_obj(NULL); diff --git a/src/hotspot/cpu/ppc/jniTypes_ppc.hpp b/src/hotspot/cpu/ppc/jniTypes_ppc.hpp index 7179e998931..6a6ecd24390 100644 --- a/src/hotspot/cpu/ppc/jniTypes_ppc.hpp +++ b/src/hotspot/cpu/ppc/jniTypes_ppc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2013 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,9 +26,9 @@ #ifndef CPU_PPC_VM_JNITYPES_PPC_HPP #define CPU_PPC_VM_JNITYPES_PPC_HPP +#include "jni.h" #include "memory/allocation.hpp" #include "oops/oop.hpp" -#include "prims/jni.h" // This file holds platform-dependent routines used to write primitive // jni types to the array of arguments passed into JavaCalls::call. diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 9ce7be54a84..bce57c7e137 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -129,7 +129,7 @@ void MacroAssembler::calculate_address_from_global_toc(Register dst, address add } } -int MacroAssembler::patch_calculate_address_from_global_toc_at(address a, address bound, address addr) { +address MacroAssembler::patch_calculate_address_from_global_toc_at(address a, address bound, address addr) { const int offset = MacroAssembler::offset_to_global_toc(addr); const address inst2_addr = a; @@ -155,7 +155,7 @@ int MacroAssembler::patch_calculate_address_from_global_toc_at(address a, addres assert(is_addis(inst1) && inv_ra_field(inst1) == 29 /* R29 */, "source must be global TOC"); set_imm((int *)inst1_addr, MacroAssembler::largeoffset_si16_si16_hi(offset)); set_imm((int *)inst2_addr, MacroAssembler::largeoffset_si16_si16_lo(offset)); - return (int)((intptr_t)addr - (intptr_t)inst1_addr); + return inst1_addr; } address MacroAssembler::get_address_of_calculate_address_from_global_toc_at(address a, address bound) { @@ -201,7 +201,7 @@ address MacroAssembler::get_address_of_calculate_address_from_global_toc_at(addr // clrldi rx = rx & 0xFFFFffff // clearMS32b, optional // ori rx = rx | const.lo // Clrldi will be passed by. -int MacroAssembler::patch_set_narrow_oop(address a, address bound, narrowOop data) { +address MacroAssembler::patch_set_narrow_oop(address a, address bound, narrowOop data) { assert(UseCompressedOops, "Should only patch compressed oops"); const address inst2_addr = a; @@ -227,7 +227,7 @@ int MacroAssembler::patch_set_narrow_oop(address a, address bound, narrowOop dat set_imm((int *)inst1_addr, (short)(xc)); // see enc_load_con_narrow_hi/_lo set_imm((int *)inst2_addr, (xd)); // unsigned int - return (int)((intptr_t)inst2_addr - (intptr_t)inst1_addr); + return inst1_addr; } // Get compressed oop or klass constant. @@ -3382,6 +3382,7 @@ void MacroAssembler::load_mirror_from_const_method(Register mirror, Register con ld(mirror, in_bytes(ConstMethod::constants_offset()), const_method); ld(mirror, ConstantPool::pool_holder_offset_in_bytes(), mirror); ld(mirror, in_bytes(Klass::java_mirror_offset()), mirror); + resolve_oop_handle(mirror); } // Clear Array @@ -5234,6 +5235,40 @@ void MacroAssembler::multiply_128_x_128_loop(Register x_xstart, bind(L_post_third_loop_done); } // multiply_128_x_128_loop +void MacroAssembler::muladd(Register out, Register in, + Register offset, Register len, Register k, + Register tmp1, Register tmp2, Register carry) { + + // Labels + Label LOOP, SKIP; + + // Make sure length is positive. + cmpdi (CCR0, len, 0); + + // Prepare variables + subi (offset, offset, 4); + li (carry, 0); + ble (CCR0, SKIP); + + mtctr (len); + subi (len, len, 1 ); + sldi (len, len, 2 ); + + // Main loop + bind(LOOP); + lwzx (tmp1, len, in ); + lwzx (tmp2, offset, out ); + mulld (tmp1, tmp1, k ); + add (tmp2, carry, tmp2 ); + add (tmp2, tmp1, tmp2 ); + stwx (tmp2, offset, out ); + srdi (carry, tmp2, 32 ); + subi (offset, offset, 4 ); + subi (len, len, 4 ); + bdnz (LOOP); + bind(SKIP); +} + void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen, diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index db04a3700e7..f1fe2385907 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -105,13 +105,15 @@ class MacroAssembler: public Assembler { }; inline static bool is_calculate_address_from_global_toc_at(address a, address bound); - static int patch_calculate_address_from_global_toc_at(address a, address addr, address bound); + // Returns address of first instruction in sequence. + static address patch_calculate_address_from_global_toc_at(address a, address bound, address addr); static address get_address_of_calculate_address_from_global_toc_at(address a, address addr); #ifdef _LP64 // Patch narrow oop constant. inline static bool is_set_narrow_oop(address a, address bound); - static int patch_set_narrow_oop(address a, address bound, narrowOop data); + // Returns address of first instruction in sequence. + static address patch_set_narrow_oop(address a, address bound, narrowOop data); static narrowOop get_narrow_oop(address a, address bound); #endif @@ -813,6 +815,8 @@ class MacroAssembler: public Assembler { Register yz_idx, Register idx, Register carry, Register product_high, Register product, Register carry2, Register tmp); + void muladd(Register out, Register in, Register offset, Register len, Register k, + Register tmp1, Register tmp2, Register carry); void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen, @@ -862,6 +866,40 @@ class MacroAssembler: public Assembler { void kernel_crc32_singleByteReg(Register crc, Register val, Register table, bool invertCRC); + // SHA-2 auxiliary functions and public interfaces + private: + void sha256_deque(const VectorRegister src, + const VectorRegister dst1, const VectorRegister dst2, const VectorRegister dst3); + void sha256_load_h_vec(const VectorRegister a, const VectorRegister e, const Register hptr); + void sha256_round(const VectorRegister* hs, const int total_hs, int& h_cnt, const VectorRegister kpw); + void sha256_load_w_plus_k_vec(const Register buf_in, const VectorRegister* ws, + const int total_ws, const Register k, const VectorRegister* kpws, + const int total_kpws); + void sha256_calc_4w(const VectorRegister w0, const VectorRegister w1, + const VectorRegister w2, const VectorRegister w3, const VectorRegister kpw0, + const VectorRegister kpw1, const VectorRegister kpw2, const VectorRegister kpw3, + const Register j, const Register k); + void sha256_update_sha_state(const VectorRegister a, const VectorRegister b, + const VectorRegister c, const VectorRegister d, const VectorRegister e, + const VectorRegister f, const VectorRegister g, const VectorRegister h, + const Register hptr); + + void sha512_load_w_vec(const Register buf_in, const VectorRegister* ws, const int total_ws); + void sha512_update_sha_state(const Register state, const VectorRegister* hs, const int total_hs); + void sha512_round(const VectorRegister* hs, const int total_hs, int& h_cnt, const VectorRegister kpw); + void sha512_load_h_vec(const Register state, const VectorRegister* hs, const int total_hs); + void sha512_calc_2w(const VectorRegister w0, const VectorRegister w1, + const VectorRegister w2, const VectorRegister w3, + const VectorRegister w4, const VectorRegister w5, + const VectorRegister w6, const VectorRegister w7, + const VectorRegister kpw0, const VectorRegister kpw1, const Register j, + const VectorRegister vRb, const Register k); + + public: + void sha256(bool multi_block); + void sha512(bool multi_block); + + // // Debugging // diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc_sha.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc_sha.cpp new file mode 100644 index 00000000000..7a82ed3f99d --- /dev/null +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc_sha.cpp @@ -0,0 +1,1136 @@ +// Copyright (c) 2017 Instituto de Pesquisas Eldorado. 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. + +// Implemented according to "Descriptions of SHA-256, SHA-384, and SHA-512" +// (http://www.iwar.org.uk/comsec/resources/cipher/sha256-384-512.pdf). + +#include "asm/macroAssembler.inline.hpp" +#include "runtime/stubRoutines.hpp" + +/********************************************************************** + * SHA 256 + *********************************************************************/ + +void MacroAssembler::sha256_deque(const VectorRegister src, + const VectorRegister dst1, + const VectorRegister dst2, + const VectorRegister dst3) { + vsldoi (dst1, src, src, 12); + vsldoi (dst2, src, src, 8); + vsldoi (dst3, src, src, 4); +} + +void MacroAssembler::sha256_round(const VectorRegister* hs, + const int total_hs, + int& h_cnt, + const VectorRegister kpw) { + // convenience registers: cycle from 0-7 downwards + const VectorRegister a = hs[(total_hs + 0 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister b = hs[(total_hs + 1 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister c = hs[(total_hs + 2 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister d = hs[(total_hs + 3 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister e = hs[(total_hs + 4 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister f = hs[(total_hs + 5 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister g = hs[(total_hs + 6 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister h = hs[(total_hs + 7 - (h_cnt % total_hs)) % total_hs]; + // temporaries + VectorRegister ch = VR0; + VectorRegister maj = VR1; + VectorRegister bsa = VR2; + VectorRegister bse = VR3; + VectorRegister vt0 = VR4; + VectorRegister vt1 = VR5; + VectorRegister vt2 = VR6; + VectorRegister vt3 = VR7; + + vsel (ch, g, f, e); + vxor (maj, a, b); + vshasigmaw (bse, e, 1, 0xf); + vadduwm (vt2, ch, kpw); + vadduwm (vt1, h, bse); + vsel (maj, b, c, maj); + vadduwm (vt3, vt1, vt2); + vshasigmaw (bsa, a, 1, 0); + vadduwm (vt0, bsa, maj); + + vadduwm (d, d, vt3); + vadduwm (h, vt3, vt0); + + // advance vector pointer to the next iteration + h_cnt++; +} + +void MacroAssembler::sha256_load_h_vec(const VectorRegister a, + const VectorRegister e, + const Register hptr) { + // temporaries + Register tmp = R8; + VectorRegister vt0 = VR0; + VectorRegister vRb = VR6; + // labels + Label sha256_aligned; + + andi_ (tmp, hptr, 0xf); + lvx (a, hptr); + addi (tmp, hptr, 16); + lvx (e, tmp); + beq (CCR0, sha256_aligned); + + // handle unaligned accesses + load_perm(vRb, hptr); + addi (tmp, hptr, 32); + vec_perm(a, e, vRb); + + lvx (vt0, tmp); + vec_perm(e, vt0, vRb); + + // aligned accesses + bind(sha256_aligned); +} + +void MacroAssembler::sha256_load_w_plus_k_vec(const Register buf_in, + const VectorRegister* ws, + const int total_ws, + const Register k, + const VectorRegister* kpws, + const int total_kpws) { + Label w_aligned, after_w_load; + + Register tmp = R8; + VectorRegister vt0 = VR0; + VectorRegister vt1 = VR1; + VectorRegister vRb = VR6; + + andi_ (tmp, buf_in, 0xF); + beq (CCR0, w_aligned); // address ends with 0x0, not 0x8 + + // deal with unaligned addresses + lvx (ws[0], buf_in); + load_perm(vRb, buf_in); + + for (int n = 1; n < total_ws; n++) { + VectorRegister w_cur = ws[n]; + VectorRegister w_prev = ws[n-1]; + + addi (tmp, buf_in, n * 16); + lvx (w_cur, tmp); + vec_perm(w_prev, w_cur, vRb); + } + addi (tmp, buf_in, total_ws * 16); + lvx (vt0, tmp); + vec_perm(ws[total_ws-1], vt0, vRb); + b (after_w_load); + + bind(w_aligned); + + // deal with aligned addresses + lvx(ws[0], buf_in); + for (int n = 1; n < total_ws; n++) { + VectorRegister w = ws[n]; + addi (tmp, buf_in, n * 16); + lvx (w, tmp); + } + + bind(after_w_load); + +#if defined(VM_LITTLE_ENDIAN) + // Byte swapping within int values + li (tmp, 8); + lvsl (vt0, tmp); + vspltisb (vt1, 0xb); + vxor (vt1, vt0, vt1); + for (int n = 0; n < total_ws; n++) { + VectorRegister w = ws[n]; + vec_perm(w, w, vt1); + } +#endif + + // Loading k, which is always aligned to 16-bytes + lvx (kpws[0], k); + for (int n = 1; n < total_kpws; n++) { + VectorRegister kpw = kpws[n]; + addi (tmp, k, 16 * n); + lvx (kpw, tmp); + } + + // Add w to K + assert(total_ws == total_kpws, "Redesign the loop below"); + for (int n = 0; n < total_kpws; n++) { + VectorRegister kpw = kpws[n]; + VectorRegister w = ws[n]; + + vadduwm (kpw, kpw, w); + } +} + +void MacroAssembler::sha256_calc_4w(const VectorRegister w0, + const VectorRegister w1, + const VectorRegister w2, + const VectorRegister w3, + const VectorRegister kpw0, + const VectorRegister kpw1, + const VectorRegister kpw2, + const VectorRegister kpw3, + const Register j, + const Register k) { + // Temporaries + const VectorRegister vt0 = VR0; + const VectorRegister vt1 = VR1; + const VectorSRegister vsrt1 = vt1->to_vsr(); + const VectorRegister vt2 = VR2; + const VectorRegister vt3 = VR3; + const VectorSRegister vst3 = vt3->to_vsr(); + const VectorRegister vt4 = VR4; + + // load to k[j] + lvx (vt0, j, k); + + // advance j + addi (j, j, 16); // 16 bytes were read + +#if defined(VM_LITTLE_ENDIAN) + // b = w[j-15], w[j-14], w[j-13], w[j-12] + vsldoi (vt1, w1, w0, 12); + + // c = w[j-7], w[j-6], w[j-5], w[j-4] + vsldoi (vt2, w3, w2, 12); + +#else + // b = w[j-15], w[j-14], w[j-13], w[j-12] + vsldoi (vt1, w0, w1, 4); + + // c = w[j-7], w[j-6], w[j-5], w[j-4] + vsldoi (vt2, w2, w3, 4); +#endif + + // d = w[j-2], w[j-1], w[j-4], w[j-3] + vsldoi (vt3, w3, w3, 8); + + // b = s0(w[j-15]) , s0(w[j-14]) , s0(w[j-13]) , s0(w[j-12]) + vshasigmaw (vt1, vt1, 0, 0); + + // d = s1(w[j-2]) , s1(w[j-1]) , s1(w[j-4]) , s1(w[j-3]) + vshasigmaw (vt3, vt3, 0, 0xf); + + // c = s0(w[j-15]) + w[j-7], + // s0(w[j-14]) + w[j-6], + // s0(w[j-13]) + w[j-5], + // s0(w[j-12]) + w[j-4] + vadduwm (vt2, vt1, vt2); + + // c = s0(w[j-15]) + w[j-7] + w[j-16], + // s0(w[j-14]) + w[j-6] + w[j-15], + // s0(w[j-13]) + w[j-5] + w[j-14], + // s0(w[j-12]) + w[j-4] + w[j-13] + vadduwm (vt2, vt2, w0); + + // e = s0(w[j-15]) + w[j-7] + w[j-16] + s1(w[j-2]), // w[j] + // s0(w[j-14]) + w[j-6] + w[j-15] + s1(w[j-1]), // w[j+1] + // s0(w[j-13]) + w[j-5] + w[j-14] + s1(w[j-4]), // UNDEFINED + // s0(w[j-12]) + w[j-4] + w[j-13] + s1(w[j-3]) // UNDEFINED + vadduwm (vt4, vt2, vt3); + + // At this point, e[0] and e[1] are the correct values to be stored at w[j] + // and w[j+1]. + // e[2] and e[3] are not considered. + // b = s1(w[j]) , s1(s(w[j+1]) , UNDEFINED , UNDEFINED + vshasigmaw (vt1, vt4, 0, 0xf); + + // v5 = s1(w[j-2]) , s1(w[j-1]) , s1(w[j]) , s1(w[j+1]) +#if defined(VM_LITTLE_ENDIAN) + xxmrgld (vst3, vsrt1, vst3); +#else + xxmrghd (vst3, vst3, vsrt1); +#endif + + // c = s0(w[j-15]) + w[j-7] + w[j-16] + s1(w[j-2]), // w[j] + // s0(w[j-14]) + w[j-6] + w[j-15] + s1(w[j-1]), // w[j+1] + // s0(w[j-13]) + w[j-5] + w[j-14] + s1(w[j]), // w[j+2] + // s0(w[j-12]) + w[j-4] + w[j-13] + s1(w[j+1]) // w[j+4] + vadduwm (vt2, vt2, vt3); + + // Updating w0 to w3 to hold the new previous 16 values from w. + vmr (w0, w1); + vmr (w1, w2); + vmr (w2, w3); + vmr (w3, vt2); + + // store k + w to v9 (4 values at once) +#if defined(VM_LITTLE_ENDIAN) + vadduwm (kpw0, vt2, vt0); + + vsldoi (kpw1, kpw0, kpw0, 12); + vsldoi (kpw2, kpw0, kpw0, 8); + vsldoi (kpw3, kpw0, kpw0, 4); +#else + vadduwm (kpw3, vt2, vt0); + + vsldoi (kpw2, kpw3, kpw3, 12); + vsldoi (kpw1, kpw3, kpw3, 8); + vsldoi (kpw0, kpw3, kpw3, 4); +#endif +} + +void MacroAssembler::sha256_update_sha_state(const VectorRegister a, + const VectorRegister b_, + const VectorRegister c, + const VectorRegister d, + const VectorRegister e, + const VectorRegister f, + const VectorRegister g, + const VectorRegister h, + const Register hptr) { + // temporaries + VectorRegister vt0 = VR0; + VectorRegister vt1 = VR1; + VectorRegister vt2 = VR2; + VectorRegister vt3 = VR3; + VectorRegister vt4 = VR4; + VectorRegister vt5 = VR5; + VectorRegister vaux = VR6; + VectorRegister vRb = VR6; + Register tmp = R8; + Register of16 = R8; + Register of32 = R9; + Label state_load_aligned; + + // Load hptr + andi_ (tmp, hptr, 0xf); + li (of16, 16); + lvx (vt0, hptr); + lvx (vt5, of16, hptr); + beq (CCR0, state_load_aligned); + + // handle unaligned accesses + li (of32, 32); + load_perm(vRb, hptr); + + vec_perm(vt0, vt5, vRb); // vt0 = hptr[0]..hptr[3] + + lvx (vt1, hptr, of32); + vec_perm(vt5, vt1, vRb); // vt5 = hptr[4]..hptr[7] + + // aligned accesses + bind(state_load_aligned); + +#if defined(VM_LITTLE_ENDIAN) + vmrglw (vt1, b_, a); // vt1 = {a, b, ?, ?} + vmrglw (vt2, d, c); // vt2 = {c, d, ?, ?} + vmrglw (vt3, f, e); // vt3 = {e, f, ?, ?} + vmrglw (vt4, h, g); // vt4 = {g, h, ?, ?} + xxmrgld (vt1->to_vsr(), vt2->to_vsr(), vt1->to_vsr()); // vt1 = {a, b, c, d} + xxmrgld (vt3->to_vsr(), vt4->to_vsr(), vt3->to_vsr()); // vt3 = {e, f, g, h} + vadduwm (a, vt0, vt1); // a = {a+hptr[0], b+hptr[1], c+hptr[2], d+hptr[3]} + vadduwm (e, vt5, vt3); // e = {e+hptr[4], f+hptr[5], g+hptr[6], h+hptr[7]} + + // Save hptr back, works for any alignment + xxswapd (vt0->to_vsr(), a->to_vsr()); + stxvd2x (vt0->to_vsr(), hptr); + xxswapd (vt5->to_vsr(), e->to_vsr()); + stxvd2x (vt5->to_vsr(), of16, hptr); +#else + vmrglw (vt1, a, b_); // vt1 = {a, b, ?, ?} + vmrglw (vt2, c, d); // vt2 = {c, d, ?, ?} + vmrglw (vt3, e, f); // vt3 = {e, f, ?, ?} + vmrglw (vt4, g, h); // vt4 = {g, h, ?, ?} + xxmrgld (vt1->to_vsr(), vt1->to_vsr(), vt2->to_vsr()); // vt1 = {a, b, c, d} + xxmrgld (vt3->to_vsr(), vt3->to_vsr(), vt4->to_vsr()); // vt3 = {e, f, g, h} + vadduwm (d, vt0, vt1); // d = {a+hptr[0], b+hptr[1], c+hptr[2], d+hptr[3]} + vadduwm (h, vt5, vt3); // h = {e+hptr[4], f+hptr[5], g+hptr[6], h+hptr[7]} + + // Save hptr back, works for any alignment + stxvd2x (d->to_vsr(), hptr); + stxvd2x (h->to_vsr(), of16, hptr); +#endif +} + +static const uint32_t sha256_round_table[64] __attribute((aligned(16))) = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +}; +static const uint32_t *sha256_round_consts = sha256_round_table; + +// R3_ARG1 - byte[] Input string with padding but in Big Endian +// R4_ARG2 - int[] SHA.state (at first, the root of primes) +// R5_ARG3 - int offset +// R6_ARG4 - int limit +// +// Internal Register usage: +// R7 - k +// R8 - tmp | j | of16 +// R9 - of32 +// VR0-VR8 - ch, maj, bsa, bse, vt0-vt3 | vt0-vt5, vaux/vRb +// VR9-VR16 - a-h +// VR17-VR20 - w0-w3 +// VR21-VR23 - vRb | vaux0-vaux2 +// VR24-VR27 - kpw0-kpw3 +void MacroAssembler::sha256(bool multi_block) { + static const ssize_t buf_size = 64; + static const uint8_t w_size = sizeof(sha256_round_table)/sizeof(uint32_t); +#ifdef AIX + // malloc provides 16 byte alignment + if (((uintptr_t)sha256_round_consts & 0xF) != 0) { + uint32_t *new_round_consts = (uint32_t*)malloc(sizeof(sha256_round_table)); + guarantee(new_round_consts, "oom"); + memcpy(new_round_consts, sha256_round_consts, sizeof(sha256_round_table)); + sha256_round_consts = (const uint32_t*)new_round_consts; + } +#endif + + Register buf_in = R3_ARG1; + Register state = R4_ARG2; + Register ofs = R5_ARG3; + Register limit = R6_ARG4; + + Label sha_loop, core_loop; + + // Save non-volatile vector registers in the red zone + static const VectorRegister nv[] = { + VR20, VR21, VR22, VR23, VR24, VR25, VR26, VR27/*, VR28, VR29, VR30, VR31*/ + }; + static const uint8_t nv_size = sizeof(nv) / sizeof (VectorRegister); + + for (int c = 0; c < nv_size; c++) { + Register tmp = R8; + li (tmp, (c - (nv_size)) * 16); + stvx(nv[c], tmp, R1); + } + + // Load hash state to registers + VectorRegister a = VR9; + VectorRegister b = VR10; + VectorRegister c = VR11; + VectorRegister d = VR12; + VectorRegister e = VR13; + VectorRegister f = VR14; + VectorRegister g = VR15; + VectorRegister h = VR16; + static const VectorRegister hs[] = {a, b, c, d, e, f, g, h}; + static const int total_hs = sizeof(hs)/sizeof(VectorRegister); + // counter for cycling through hs vector to avoid register moves between iterations + int h_cnt = 0; + + // Load a-h registers from the memory pointed by state +#if defined(VM_LITTLE_ENDIAN) + sha256_load_h_vec(a, e, state); +#else + sha256_load_h_vec(d, h, state); +#endif + + // keep k loaded also during MultiBlock loops + Register k = R7; + assert(((uintptr_t)sha256_round_consts & 0xF) == 0, "k alignment"); + load_const_optimized(k, (address)sha256_round_consts, R0); + + // Avoiding redundant loads + if (multi_block) { + align(OptoLoopAlignment); + } + bind(sha_loop); +#if defined(VM_LITTLE_ENDIAN) + sha256_deque(a, b, c, d); + sha256_deque(e, f, g, h); +#else + sha256_deque(d, c, b, a); + sha256_deque(h, g, f, e); +#endif + + // Load 16 elements from w out of the loop. + // Order of the int values is Endianess specific. + VectorRegister w0 = VR17; + VectorRegister w1 = VR18; + VectorRegister w2 = VR19; + VectorRegister w3 = VR20; + static const VectorRegister ws[] = {w0, w1, w2, w3}; + static const int total_ws = sizeof(ws)/sizeof(VectorRegister); + + VectorRegister kpw0 = VR24; + VectorRegister kpw1 = VR25; + VectorRegister kpw2 = VR26; + VectorRegister kpw3 = VR27; + static const VectorRegister kpws[] = {kpw0, kpw1, kpw2, kpw3}; + static const int total_kpws = sizeof(kpws)/sizeof(VectorRegister); + + sha256_load_w_plus_k_vec(buf_in, ws, total_ws, k, kpws, total_kpws); + + // Cycle through the first 16 elements + assert(total_ws == total_kpws, "Redesign the loop below"); + for (int n = 0; n < total_ws; n++) { + VectorRegister vaux0 = VR21; + VectorRegister vaux1 = VR22; + VectorRegister vaux2 = VR23; + + sha256_deque(kpws[n], vaux0, vaux1, vaux2); + +#if defined(VM_LITTLE_ENDIAN) + sha256_round(hs, total_hs, h_cnt, kpws[n]); + sha256_round(hs, total_hs, h_cnt, vaux0); + sha256_round(hs, total_hs, h_cnt, vaux1); + sha256_round(hs, total_hs, h_cnt, vaux2); +#else + sha256_round(hs, total_hs, h_cnt, vaux2); + sha256_round(hs, total_hs, h_cnt, vaux1); + sha256_round(hs, total_hs, h_cnt, vaux0); + sha256_round(hs, total_hs, h_cnt, kpws[n]); +#endif + } + + Register tmp = R8; + // loop the 16th to the 64th iteration by 8 steps + li (tmp, (w_size - 16) / total_hs); + mtctr(tmp); + + // j will be aligned to 4 for loading words. + // Whenever read, advance the pointer (e.g: when j is used in a function) + Register j = R8; + li (j, 16*4); + + align(OptoLoopAlignment); + bind(core_loop); + + // due to VectorRegister rotate, always iterate in multiples of total_hs + for (int n = 0; n < total_hs/4; n++) { + sha256_calc_4w(w0, w1, w2, w3, kpw0, kpw1, kpw2, kpw3, j, k); + sha256_round(hs, total_hs, h_cnt, kpw0); + sha256_round(hs, total_hs, h_cnt, kpw1); + sha256_round(hs, total_hs, h_cnt, kpw2); + sha256_round(hs, total_hs, h_cnt, kpw3); + } + + bdnz (core_loop); + + // Update hash state + sha256_update_sha_state(a, b, c, d, e, f, g, h, state); + + if (multi_block) { + addi(buf_in, buf_in, buf_size); + addi(ofs, ofs, buf_size); + cmplw(CCR0, ofs, limit); + ble(CCR0, sha_loop); + + // return ofs + mr(R3_RET, ofs); + } + + // Restore non-volatile registers + for (int c = 0; c < nv_size; c++) { + Register tmp = R8; + li (tmp, (c - (nv_size)) * 16); + lvx(nv[c], tmp, R1); + } +} + + +/********************************************************************** + * SHA 512 + *********************************************************************/ + +void MacroAssembler::sha512_load_w_vec(const Register buf_in, + const VectorRegister* ws, + const int total_ws) { + Register tmp = R8; + VectorRegister vRb = VR8; + VectorRegister aux = VR9; + Label is_aligned, after_alignment; + + andi_ (tmp, buf_in, 0xF); + beq (CCR0, is_aligned); // address ends with 0x0, not 0x8 + + // deal with unaligned addresses + lvx (ws[0], buf_in); + load_perm(vRb, buf_in); + + for (int n = 1; n < total_ws; n++) { + VectorRegister w_cur = ws[n]; + VectorRegister w_prev = ws[n-1]; + addi (tmp, buf_in, n * 16); + lvx (w_cur, tmp); + vec_perm(w_prev, w_cur, vRb); + } + addi (tmp, buf_in, total_ws * 16); + lvx (aux, tmp); + vec_perm(ws[total_ws-1], aux, vRb); + b (after_alignment); + + bind(is_aligned); + lvx (ws[0], buf_in); + for (int n = 1; n < total_ws; n++) { + VectorRegister w = ws[n]; + addi (tmp, buf_in, n * 16); + lvx (w, tmp); + } + + bind(after_alignment); +} + +// Update hash state +void MacroAssembler::sha512_update_sha_state(const Register state, + const VectorRegister* hs, + const int total_hs) { + +#if defined(VM_LITTLE_ENDIAN) + int start_idx = 0; +#else + int start_idx = 1; +#endif + + // load initial hash from the memory pointed by state + VectorRegister ini_a = VR10; + VectorRegister ini_c = VR12; + VectorRegister ini_e = VR14; + VectorRegister ini_g = VR16; + static const VectorRegister inis[] = {ini_a, ini_c, ini_e, ini_g}; + static const int total_inis = sizeof(inis)/sizeof(VectorRegister); + + Label state_save_aligned, after_state_save_aligned; + + Register addr = R7; + Register tmp = R8; + VectorRegister vRb = VR8; + VectorRegister aux = VR9; + + andi_(tmp, state, 0xf); + beq(CCR0, state_save_aligned); + // deal with unaligned addresses + + { + VectorRegister a = hs[0]; + VectorRegister b_ = hs[1]; + VectorRegister c = hs[2]; + VectorRegister d = hs[3]; + VectorRegister e = hs[4]; + VectorRegister f = hs[5]; + VectorRegister g = hs[6]; + VectorRegister h = hs[7]; + load_perm(vRb, state); + lvx (ini_a, state); + addi (addr, state, 16); + + lvx (ini_c, addr); + addi (addr, state, 32); + vec_perm(ini_a, ini_c, vRb); + + lvx (ini_e, addr); + addi (addr, state, 48); + vec_perm(ini_c, ini_e, vRb); + + lvx (ini_g, addr); + addi (addr, state, 64); + vec_perm(ini_e, ini_g, vRb); + + lvx (aux, addr); + vec_perm(ini_g, aux, vRb); + +#if defined(VM_LITTLE_ENDIAN) + xxmrgld(a->to_vsr(), b_->to_vsr(), a->to_vsr()); + xxmrgld(c->to_vsr(), d->to_vsr(), c->to_vsr()); + xxmrgld(e->to_vsr(), f->to_vsr(), e->to_vsr()); + xxmrgld(g->to_vsr(), h->to_vsr(), g->to_vsr()); +#else + xxmrgld(b_->to_vsr(), a->to_vsr(), b_->to_vsr()); + xxmrgld(d->to_vsr(), c->to_vsr(), d->to_vsr()); + xxmrgld(f->to_vsr(), e->to_vsr(), f->to_vsr()); + xxmrgld(h->to_vsr(), g->to_vsr(), h->to_vsr()); +#endif + + for (int n = start_idx; n < total_hs; n += 2) { + VectorRegister h_cur = hs[n]; + VectorRegister ini_cur = inis[n/2]; + + vaddudm(h_cur, ini_cur, h_cur); + } + + for (int n = start_idx; n < total_hs; n += 2) { + VectorRegister h_cur = hs[n]; + + mfvrd (tmp, h_cur); +#if defined(VM_LITTLE_ENDIAN) + std (tmp, 8*n + 8, state); +#else + std (tmp, 8*n - 8, state); +#endif + vsldoi (aux, h_cur, h_cur, 8); + mfvrd (tmp, aux); + std (tmp, 8*n + 0, state); + } + + b (after_state_save_aligned); + } + + bind(state_save_aligned); + { + for (int n = 0; n < total_hs; n += 2) { +#if defined(VM_LITTLE_ENDIAN) + VectorRegister h_cur = hs[n]; + VectorRegister h_next = hs[n+1]; +#else + VectorRegister h_cur = hs[n+1]; + VectorRegister h_next = hs[n]; +#endif + VectorRegister ini_cur = inis[n/2]; + + if (n/2 == 0) { + lvx(ini_cur, state); + } else { + addi(addr, state, (n/2) * 16); + lvx(ini_cur, addr); + } + xxmrgld(h_cur->to_vsr(), h_next->to_vsr(), h_cur->to_vsr()); + } + + for (int n = start_idx; n < total_hs; n += 2) { + VectorRegister h_cur = hs[n]; + VectorRegister ini_cur = inis[n/2]; + + vaddudm(h_cur, ini_cur, h_cur); + } + + for (int n = start_idx; n < total_hs; n += 2) { + VectorRegister h_cur = hs[n]; + + if (n/2 == 0) { + stvx(h_cur, state); + } else { + addi(addr, state, (n/2) * 16); + stvx(h_cur, addr); + } + } + } + + bind(after_state_save_aligned); +} + +// Use h_cnt to cycle through hs elements but also increment it at the end +void MacroAssembler::sha512_round(const VectorRegister* hs, + const int total_hs, int& h_cnt, + const VectorRegister kpw) { + + // convenience registers: cycle from 0-7 downwards + const VectorRegister a = hs[(total_hs + 0 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister b = hs[(total_hs + 1 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister c = hs[(total_hs + 2 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister d = hs[(total_hs + 3 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister e = hs[(total_hs + 4 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister f = hs[(total_hs + 5 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister g = hs[(total_hs + 6 - (h_cnt % total_hs)) % total_hs]; + const VectorRegister h = hs[(total_hs + 7 - (h_cnt % total_hs)) % total_hs]; + // temporaries + const VectorRegister Ch = VR20; + const VectorRegister Maj = VR21; + const VectorRegister bsa = VR22; + const VectorRegister bse = VR23; + const VectorRegister tmp1 = VR24; + const VectorRegister tmp2 = VR25; + + vsel (Ch, g, f, e); + vxor (Maj, a, b); + vshasigmad(bse, e, 1, 0xf); + vaddudm (tmp2, Ch, kpw); + vaddudm (tmp1, h, bse); + vsel (Maj, b, c, Maj); + vaddudm (tmp1, tmp1, tmp2); + vshasigmad(bsa, a, 1, 0); + vaddudm (tmp2, bsa, Maj); + vaddudm (d, d, tmp1); + vaddudm (h, tmp1, tmp2); + + // advance vector pointer to the next iteration + h_cnt++; +} + +void MacroAssembler::sha512_calc_2w(const VectorRegister w0, + const VectorRegister w1, + const VectorRegister w2, + const VectorRegister w3, + const VectorRegister w4, + const VectorRegister w5, + const VectorRegister w6, + const VectorRegister w7, + const VectorRegister kpw0, + const VectorRegister kpw1, + const Register j, + const VectorRegister vRb, + const Register k) { + // Temporaries + const VectorRegister VR_a = VR20; + const VectorRegister VR_b = VR21; + const VectorRegister VR_c = VR22; + const VectorRegister VR_d = VR23; + + // load to k[j] + lvx (VR_a, j, k); + // advance j + addi (j, j, 16); // 16 bytes were read + +#if defined(VM_LITTLE_ENDIAN) + // v6 = w[j-15], w[j-14] + vperm (VR_b, w1, w0, vRb); + // v12 = w[j-7], w[j-6] + vperm (VR_c, w5, w4, vRb); +#else + // v6 = w[j-15], w[j-14] + vperm (VR_b, w0, w1, vRb); + // v12 = w[j-7], w[j-6] + vperm (VR_c, w4, w5, vRb); +#endif + + // v6 = s0(w[j-15]) , s0(w[j-14]) + vshasigmad (VR_b, VR_b, 0, 0); + // v5 = s1(w[j-2]) , s1(w[j-1]) + vshasigmad (VR_d, w7, 0, 0xf); + // v6 = s0(w[j-15]) + w[j-7] , s0(w[j-14]) + w[j-6] + vaddudm (VR_b, VR_b, VR_c); + // v8 = s1(w[j-2]) + w[j-16] , s1(w[j-1]) + w[j-15] + vaddudm (VR_d, VR_d, w0); + // v9 = s0(w[j-15]) + w[j-7] + w[j-16] + s1(w[j-2]), // w[j] + // s0(w[j-14]) + w[j-6] + w[j-15] + s1(w[j-1]), // w[j+1] + vaddudm (VR_c, VR_d, VR_b); + // Updating w0 to w7 to hold the new previous 16 values from w. + vmr (w0, w1); + vmr (w1, w2); + vmr (w2, w3); + vmr (w3, w4); + vmr (w4, w5); + vmr (w5, w6); + vmr (w6, w7); + vmr (w7, VR_c); + +#if defined(VM_LITTLE_ENDIAN) + // store k + w to kpw0 (2 values at once) + vaddudm (kpw0, VR_c, VR_a); + // kpw1 holds (k + w)[1] + vsldoi (kpw1, kpw0, kpw0, 8); +#else + // store k + w to kpw0 (2 values at once) + vaddudm (kpw1, VR_c, VR_a); + // kpw1 holds (k + w)[1] + vsldoi (kpw0, kpw1, kpw1, 8); +#endif +} + +void MacroAssembler::sha512_load_h_vec(const Register state, + const VectorRegister* hs, + const int total_hs) { +#if defined(VM_LITTLE_ENDIAN) + VectorRegister a = hs[0]; + VectorRegister g = hs[6]; + int start_idx = 0; +#else + VectorRegister a = hs[1]; + VectorRegister g = hs[7]; + int start_idx = 1; +#endif + + Register addr = R7; + VectorRegister vRb = VR8; + Register tmp = R8; + Label state_aligned, after_state_aligned; + + andi_(tmp, state, 0xf); + beq(CCR0, state_aligned); + + // deal with unaligned addresses + VectorRegister aux = VR9; + + lvx(hs[start_idx], state); + load_perm(vRb, state); + + for (int n = start_idx + 2; n < total_hs; n += 2) { + VectorRegister h_cur = hs[n]; + VectorRegister h_prev2 = hs[n - 2]; + addi(addr, state, (n/2) * 16); + lvx(h_cur, addr); + vec_perm(h_prev2, h_cur, vRb); + } + addi(addr, state, (total_hs/2) * 16); + lvx (aux, addr); + vec_perm(hs[total_hs - 2 + start_idx], aux, vRb); + b (after_state_aligned); + + bind(state_aligned); + + // deal with aligned addresses + lvx(hs[start_idx], state); + + for (int n = start_idx + 2; n < total_hs; n += 2) { + VectorRegister h_cur = hs[n]; + addi(addr, state, (n/2) * 16); + lvx(h_cur, addr); + } + + bind(after_state_aligned); +} + +static const uint64_t sha512_round_table[80] __attribute((aligned(16))) = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, + 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, + 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, 0x12835b0145706fbe, + 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, + 0x9bdc06a725c71235, 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, + 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, + 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, + 0x06ca6351e003826f, 0x142929670a0e6e70, + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, + 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, + 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, + 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, + 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, + 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, 0x78a5636f43172f60, + 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, + 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + 0xca273eceea26619c, 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, + 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, + 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, +}; +static const uint64_t *sha512_round_consts = sha512_round_table; + +// R3_ARG1 - byte[] Input string with padding but in Big Endian +// R4_ARG2 - int[] SHA.state (at first, the root of primes) +// R5_ARG3 - int offset +// R6_ARG4 - int limit +// +// Internal Register usage: +// R7 R8 R9 - volatile temporaries +// VR0-VR7 - a-h +// VR8 - vRb +// VR9 - aux (highly volatile, use with care) +// VR10-VR17 - w0-w7 | ini_a-ini_h +// VR18 - vsp16 | kplusw0 +// VR19 - vsp32 | kplusw1 +// VR20-VR25 - sha512_calc_2w and sha512_round temporaries +void MacroAssembler::sha512(bool multi_block) { + static const ssize_t buf_size = 128; + static const uint8_t w_size = sizeof(sha512_round_table)/sizeof(uint64_t); +#ifdef AIX + // malloc provides 16 byte alignment + if (((uintptr_t)sha512_round_consts & 0xF) != 0) { + uint64_t *new_round_consts = (uint64_t*)malloc(sizeof(sha512_round_table)); + guarantee(new_round_consts, "oom"); + memcpy(new_round_consts, sha512_round_consts, sizeof(sha512_round_table)); + sha512_round_consts = (const uint64_t*)new_round_consts; + } +#endif + + Register buf_in = R3_ARG1; + Register state = R4_ARG2; + Register ofs = R5_ARG3; + Register limit = R6_ARG4; + + Label sha_loop, core_loop; + + // Save non-volatile vector registers in the red zone + static const VectorRegister nv[] = { + VR20, VR21, VR22, VR23, VR24, VR25/*, VR26, VR27, VR28, VR29, VR30, VR31*/ + }; + static const uint8_t nv_size = sizeof(nv) / sizeof (VectorRegister); + + for (int c = 0; c < nv_size; c++) { + Register idx = R7; + li (idx, (c - (nv_size)) * 16); + stvx(nv[c], idx, R1); + } + + // Load hash state to registers + VectorRegister a = VR0; + VectorRegister b = VR1; + VectorRegister c = VR2; + VectorRegister d = VR3; + VectorRegister e = VR4; + VectorRegister f = VR5; + VectorRegister g = VR6; + VectorRegister h = VR7; + static const VectorRegister hs[] = {a, b, c, d, e, f, g, h}; + static const int total_hs = sizeof(hs)/sizeof(VectorRegister); + // counter for cycling through hs vector to avoid register moves between iterations + int h_cnt = 0; + + // Load a-h registers from the memory pointed by state + sha512_load_h_vec(state, hs, total_hs); + + Register k = R9; + assert(((uintptr_t)sha512_round_consts & 0xF) == 0, "k alignment"); + load_const_optimized(k, (address)sha512_round_consts, R0); + + if (multi_block) { + align(OptoLoopAlignment); + } + bind(sha_loop); + + for (int n = 0; n < total_hs; n += 2) { +#if defined(VM_LITTLE_ENDIAN) + VectorRegister h_cur = hs[n]; + VectorRegister h_next = hs[n + 1]; +#else + VectorRegister h_cur = hs[n + 1]; + VectorRegister h_next = hs[n]; +#endif + vsldoi (h_next, h_cur, h_cur, 8); + } + + // Load 16 elements from w out of the loop. + // Order of the long values is Endianess specific. + VectorRegister w0 = VR10; + VectorRegister w1 = VR11; + VectorRegister w2 = VR12; + VectorRegister w3 = VR13; + VectorRegister w4 = VR14; + VectorRegister w5 = VR15; + VectorRegister w6 = VR16; + VectorRegister w7 = VR17; + static const VectorRegister ws[] = {w0, w1, w2, w3, w4, w5, w6, w7}; + static const int total_ws = sizeof(ws)/sizeof(VectorRegister); + + // Load 16 w into vectors and setup vsl for vperm + sha512_load_w_vec(buf_in, ws, total_ws); + +#if defined(VM_LITTLE_ENDIAN) + VectorRegister vsp16 = VR18; + VectorRegister vsp32 = VR19; + VectorRegister shiftarg = VR9; + + vspltisw(vsp16, 8); + vspltisw(shiftarg, 1); + vsl (vsp16, vsp16, shiftarg); + vsl (vsp32, vsp16, shiftarg); + + VectorRegister vsp8 = VR9; + vspltish(vsp8, 8); + + // Convert input from Big Endian to Little Endian + for (int c = 0; c < total_ws; c++) { + VectorRegister w = ws[c]; + vrlh (w, w, vsp8); + } + for (int c = 0; c < total_ws; c++) { + VectorRegister w = ws[c]; + vrlw (w, w, vsp16); + } + for (int c = 0; c < total_ws; c++) { + VectorRegister w = ws[c]; + vrld (w, w, vsp32); + } +#endif + + Register Rb = R10; + VectorRegister vRb = VR8; + li (Rb, 8); + load_perm(vRb, Rb); + + VectorRegister kplusw0 = VR18; + VectorRegister kplusw1 = VR19; + + Register addr = R7; + + for (int n = 0; n < total_ws; n++) { + VectorRegister w = ws[n]; + + if (n == 0) { + lvx (kplusw0, k); + } else { + addi (addr, k, n * 16); + lvx (kplusw0, addr); + } +#if defined(VM_LITTLE_ENDIAN) + vaddudm(kplusw0, kplusw0, w); + vsldoi (kplusw1, kplusw0, kplusw0, 8); +#else + vaddudm(kplusw1, kplusw0, w); + vsldoi (kplusw0, kplusw1, kplusw1, 8); +#endif + + sha512_round(hs, total_hs, h_cnt, kplusw0); + sha512_round(hs, total_hs, h_cnt, kplusw1); + } + + Register tmp = R8; + li (tmp, (w_size-16)/total_hs); + mtctr (tmp); + // j will be aligned to 4 for loading words. + // Whenever read, advance the pointer (e.g: when j is used in a function) + Register j = tmp; + li (j, 8*16); + + align(OptoLoopAlignment); + bind(core_loop); + + // due to VectorRegister rotate, always iterate in multiples of total_hs + for (int n = 0; n < total_hs/2; n++) { + sha512_calc_2w(w0, w1, w2, w3, w4, w5, w6, w7, kplusw0, kplusw1, j, vRb, k); + sha512_round(hs, total_hs, h_cnt, kplusw0); + sha512_round(hs, total_hs, h_cnt, kplusw1); + } + + bdnz (core_loop); + + sha512_update_sha_state(state, hs, total_hs); + + if (multi_block) { + addi(buf_in, buf_in, buf_size); + addi(ofs, ofs, buf_size); + cmplw(CCR0, ofs, limit); + ble(CCR0, sha_loop); + + // return ofs + mr(R3_RET, ofs); + } + + // Restore non-volatile registers + for (int c = 0; c < nv_size; c++) { + Register idx = R7; + li (idx, (c - (nv_size)) * 16); + lvx(nv[c], idx, R1); + } +} diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp index 70cd4ebbd91..6d6128d416e 100644 --- a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp +++ b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2015 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -221,13 +221,13 @@ address NativeMovConstReg::set_data_plain(intptr_t data, CodeBlob *cb) { // A calculation relative to the global TOC. if (MacroAssembler::get_address_of_calculate_address_from_global_toc_at(addr, cb->content_begin()) != (address)data) { - const int invalidated_range = - MacroAssembler::patch_calculate_address_from_global_toc_at(addr, cb->content_begin(), + const address inst2_addr = addr; + const address inst1_addr = + MacroAssembler::patch_calculate_address_from_global_toc_at(inst2_addr, cb->content_begin(), (address)data); - const address start = invalidated_range < 0 ? addr + invalidated_range : addr; - // FIXME: - const int range = invalidated_range < 0 ? 4 - invalidated_range : 8; - ICache::ppc64_flush_icache_bytes(start, range); + assert(inst1_addr != NULL && inst1_addr < inst2_addr, "first instruction must be found"); + const int range = inst2_addr - inst1_addr + BytesPerInstWord; + ICache::ppc64_flush_icache_bytes(inst1_addr, range); } next_address = addr + 1 * BytesPerInstWord; } else if (MacroAssembler::is_load_const_at(addr)) { @@ -288,15 +288,15 @@ void NativeMovConstReg::set_data(intptr_t data) { } void NativeMovConstReg::set_narrow_oop(narrowOop data, CodeBlob *code /* = NULL */) { - address addr = addr_at(0); + address inst2_addr = addr_at(0); CodeBlob* cb = (code) ? code : CodeCache::find_blob(instruction_address()); - if (MacroAssembler::get_narrow_oop(addr, cb->content_begin()) == (long)data) return; - const int invalidated_range = - MacroAssembler::patch_set_narrow_oop(addr, cb->content_begin(), (long)data); - const address start = invalidated_range < 0 ? addr + invalidated_range : addr; - // FIXME: - const int range = invalidated_range < 0 ? 4 - invalidated_range : 8; - ICache::ppc64_flush_icache_bytes(start, range); + if (MacroAssembler::get_narrow_oop(inst2_addr, cb->content_begin()) == (long)data) + return; + const address inst1_addr = + MacroAssembler::patch_set_narrow_oop(inst2_addr, cb->content_begin(), (long)data); + assert(inst1_addr != NULL && inst1_addr < inst2_addr, "first instruction must be found"); + const int range = inst2_addr - inst1_addr + BytesPerInstWord; + ICache::ppc64_flush_icache_bytes(inst1_addr, range); } // Do not use an assertion here. Let clients decide whether they only diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index de0d6088460..789c91f2005 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -254,6 +254,73 @@ register %{ reg_def SR_SPEFSCR(SOC, SOC, Op_RegP, 4, SR_SPEFSCR->as_VMReg()); // v reg_def SR_PPR( SOC, SOC, Op_RegP, 5, SR_PPR->as_VMReg()); // v +// ---------------------------- +// Vector-Scalar Registers +// ---------------------------- + reg_def VSR0 ( SOC, SOC, Op_VecX, 0, NULL); + reg_def VSR1 ( SOC, SOC, Op_VecX, 1, NULL); + reg_def VSR2 ( SOC, SOC, Op_VecX, 2, NULL); + reg_def VSR3 ( SOC, SOC, Op_VecX, 3, NULL); + reg_def VSR4 ( SOC, SOC, Op_VecX, 4, NULL); + reg_def VSR5 ( SOC, SOC, Op_VecX, 5, NULL); + reg_def VSR6 ( SOC, SOC, Op_VecX, 6, NULL); + reg_def VSR7 ( SOC, SOC, Op_VecX, 7, NULL); + reg_def VSR8 ( SOC, SOC, Op_VecX, 8, NULL); + reg_def VSR9 ( SOC, SOC, Op_VecX, 9, NULL); + reg_def VSR10 ( SOC, SOC, Op_VecX, 10, NULL); + reg_def VSR11 ( SOC, SOC, Op_VecX, 11, NULL); + reg_def VSR12 ( SOC, SOC, Op_VecX, 12, NULL); + reg_def VSR13 ( SOC, SOC, Op_VecX, 13, NULL); + reg_def VSR14 ( SOC, SOC, Op_VecX, 14, NULL); + reg_def VSR15 ( SOC, SOC, Op_VecX, 15, NULL); + reg_def VSR16 ( SOC, SOC, Op_VecX, 16, NULL); + reg_def VSR17 ( SOC, SOC, Op_VecX, 17, NULL); + reg_def VSR18 ( SOC, SOC, Op_VecX, 18, NULL); + reg_def VSR19 ( SOC, SOC, Op_VecX, 19, NULL); + reg_def VSR20 ( SOC, SOC, Op_VecX, 20, NULL); + reg_def VSR21 ( SOC, SOC, Op_VecX, 21, NULL); + reg_def VSR22 ( SOC, SOC, Op_VecX, 22, NULL); + reg_def VSR23 ( SOC, SOC, Op_VecX, 23, NULL); + reg_def VSR24 ( SOC, SOC, Op_VecX, 24, NULL); + reg_def VSR25 ( SOC, SOC, Op_VecX, 25, NULL); + reg_def VSR26 ( SOC, SOC, Op_VecX, 26, NULL); + reg_def VSR27 ( SOC, SOC, Op_VecX, 27, NULL); + reg_def VSR28 ( SOC, SOC, Op_VecX, 28, NULL); + reg_def VSR29 ( SOC, SOC, Op_VecX, 29, NULL); + reg_def VSR30 ( SOC, SOC, Op_VecX, 30, NULL); + reg_def VSR31 ( SOC, SOC, Op_VecX, 31, NULL); + reg_def VSR32 ( SOC, SOC, Op_VecX, 32, NULL); + reg_def VSR33 ( SOC, SOC, Op_VecX, 33, NULL); + reg_def VSR34 ( SOC, SOC, Op_VecX, 34, NULL); + reg_def VSR35 ( SOC, SOC, Op_VecX, 35, NULL); + reg_def VSR36 ( SOC, SOC, Op_VecX, 36, NULL); + reg_def VSR37 ( SOC, SOC, Op_VecX, 37, NULL); + reg_def VSR38 ( SOC, SOC, Op_VecX, 38, NULL); + reg_def VSR39 ( SOC, SOC, Op_VecX, 39, NULL); + reg_def VSR40 ( SOC, SOC, Op_VecX, 40, NULL); + reg_def VSR41 ( SOC, SOC, Op_VecX, 41, NULL); + reg_def VSR42 ( SOC, SOC, Op_VecX, 42, NULL); + reg_def VSR43 ( SOC, SOC, Op_VecX, 43, NULL); + reg_def VSR44 ( SOC, SOC, Op_VecX, 44, NULL); + reg_def VSR45 ( SOC, SOC, Op_VecX, 45, NULL); + reg_def VSR46 ( SOC, SOC, Op_VecX, 46, NULL); + reg_def VSR47 ( SOC, SOC, Op_VecX, 47, NULL); + reg_def VSR48 ( SOC, SOC, Op_VecX, 48, NULL); + reg_def VSR49 ( SOC, SOC, Op_VecX, 49, NULL); + reg_def VSR50 ( SOC, SOC, Op_VecX, 50, NULL); + reg_def VSR51 ( SOC, SOC, Op_VecX, 51, NULL); + reg_def VSR52 ( SOC, SOC, Op_VecX, 52, NULL); + reg_def VSR53 ( SOC, SOC, Op_VecX, 53, NULL); + reg_def VSR54 ( SOC, SOC, Op_VecX, 54, NULL); + reg_def VSR55 ( SOC, SOC, Op_VecX, 55, NULL); + reg_def VSR56 ( SOC, SOC, Op_VecX, 56, NULL); + reg_def VSR57 ( SOC, SOC, Op_VecX, 57, NULL); + reg_def VSR58 ( SOC, SOC, Op_VecX, 58, NULL); + reg_def VSR59 ( SOC, SOC, Op_VecX, 59, NULL); + reg_def VSR60 ( SOC, SOC, Op_VecX, 60, NULL); + reg_def VSR61 ( SOC, SOC, Op_VecX, 61, NULL); + reg_def VSR62 ( SOC, SOC, Op_VecX, 62, NULL); + reg_def VSR63 ( SOC, SOC, Op_VecX, 63, NULL); // ---------------------------- // Specify priority of register selection within phases of register @@ -385,6 +452,73 @@ alloc_class chunk2 ( ); alloc_class chunk3 ( + VSR0, + VSR1, + VSR2, + VSR3, + VSR4, + VSR5, + VSR6, + VSR7, + VSR8, + VSR9, + VSR10, + VSR11, + VSR12, + VSR13, + VSR14, + VSR15, + VSR16, + VSR17, + VSR18, + VSR19, + VSR20, + VSR21, + VSR22, + VSR23, + VSR24, + VSR25, + VSR26, + VSR27, + VSR28, + VSR29, + VSR30, + VSR31, + VSR32, + VSR33, + VSR34, + VSR35, + VSR36, + VSR37, + VSR38, + VSR39, + VSR40, + VSR41, + VSR42, + VSR43, + VSR44, + VSR45, + VSR46, + VSR47, + VSR48, + VSR49, + VSR50, + VSR51, + VSR52, + VSR53, + VSR54, + VSR55, + VSR56, + VSR57, + VSR58, + VSR59, + VSR60, + VSR61, + VSR62, + VSR63 +); + +alloc_class chunk4 ( // special registers // These registers are not allocated, but used for nodes generated by postalloc expand. SR_XER, @@ -769,6 +903,45 @@ reg_class dbl_reg( F31, F31_H // nv! ); +// ---------------------------- +// Vector-Scalar Register Class +// ---------------------------- + +reg_class vs_reg( + VSR32, + VSR33, + VSR34, + VSR35, + VSR36, + VSR37, + VSR38, + VSR39, + VSR40, + VSR41, + VSR42, + VSR43, + VSR44, + VSR45, + VSR46, + VSR47, + VSR48, + VSR49, + VSR50, + VSR51 +// VSR52, // nv! +// VSR53, // nv! +// VSR54, // nv! +// VSR55, // nv! +// VSR56, // nv! +// VSR57, // nv! +// VSR58, // nv! +// VSR59, // nv! +// VSR60, // nv! +// VSR61, // nv! +// VSR62, // nv! +// VSR63 // nv! +); + %} //----------DEFINITION BLOCK--------------------------------------------------- @@ -1502,7 +1675,7 @@ static enum RC rc_class(OptoReg::Name reg) { if (reg < 64+64) return rc_float; // Between float regs & stack are the flags regs. - assert(OptoReg::is_stack(reg), "blow up if spilling flags"); + assert(OptoReg::is_stack(reg) || reg < 64+64+64, "blow up if spilling flags"); return rc_stack; } @@ -2048,14 +2221,24 @@ const bool Matcher::convL2FSupported(void) { // Vector width in bytes. const int Matcher::vector_width_in_bytes(BasicType bt) { - assert(MaxVectorSize == 8, ""); - return 8; + if (SuperwordUseVSX) { + assert(MaxVectorSize == 16, ""); + return 16; + } else { + assert(MaxVectorSize == 8, ""); + return 8; + } } // Vector ideal reg. const uint Matcher::vector_ideal_reg(int size) { - assert(MaxVectorSize == 8 && size == 8, ""); - return Op_RegL; + if (SuperwordUseVSX) { + assert(MaxVectorSize == 16 && size == 16, ""); + return Op_VecX; + } else { + assert(MaxVectorSize == 8 && size == 8, ""); + return Op_RegL; + } } const uint Matcher::vector_shift_count_ideal_reg(int size) { @@ -2075,7 +2258,7 @@ const int Matcher::min_vector_size(const BasicType bt) { // PPC doesn't support misaligned vectors store/load. const bool Matcher::misaligned_vectors_ok() { - return false; + return !AlignVector; // can be changed by flag } // PPC AES support not yet implemented @@ -2217,10 +2400,31 @@ const MachRegisterNumbers farg_reg[13] = { F13_num }; +const MachRegisterNumbers vsarg_reg[64] = { + VSR0_num, VSR1_num, VSR2_num, VSR3_num, + VSR4_num, VSR5_num, VSR6_num, VSR7_num, + VSR8_num, VSR9_num, VSR10_num, VSR11_num, + VSR12_num, VSR13_num, VSR14_num, VSR15_num, + VSR16_num, VSR17_num, VSR18_num, VSR19_num, + VSR20_num, VSR21_num, VSR22_num, VSR23_num, + VSR24_num, VSR23_num, VSR24_num, VSR25_num, + VSR28_num, VSR29_num, VSR30_num, VSR31_num, + VSR32_num, VSR33_num, VSR34_num, VSR35_num, + VSR36_num, VSR37_num, VSR38_num, VSR39_num, + VSR40_num, VSR41_num, VSR42_num, VSR43_num, + VSR44_num, VSR45_num, VSR46_num, VSR47_num, + VSR48_num, VSR49_num, VSR50_num, VSR51_num, + VSR52_num, VSR53_num, VSR54_num, VSR55_num, + VSR56_num, VSR57_num, VSR58_num, VSR59_num, + VSR60_num, VSR61_num, VSR62_num, VSR63_num +}; + const int num_iarg_registers = sizeof(iarg_reg) / sizeof(iarg_reg[0]); const int num_farg_registers = sizeof(farg_reg) / sizeof(farg_reg[0]); +const int num_vsarg_registers = sizeof(vsarg_reg) / sizeof(vsarg_reg[0]); + // Return whether or not this register is ever used as an argument. This // function is used on startup to build the trampoline stubs in generateOptoStub. // Registers not mentioned will be killed by the VM call in the trampoline, and @@ -2552,6 +2756,115 @@ loadConLNodesTuple loadConLNodesTuple_create(PhaseRegAlloc *ra_, Node *toc, immL return nodes; } +typedef struct { + loadConL_hiNode *_large_hi; + loadConL_loNode *_large_lo; + mtvsrdNode *_moved; + xxspltdNode *_replicated; + loadConLNode *_small; + MachNode *_last; +} loadConLReplicatedNodesTuple; + +loadConLReplicatedNodesTuple loadConLReplicatedNodesTuple_create(Compile *C, PhaseRegAlloc *ra_, Node *toc, immLOper *immSrc, + vecXOper *dst, immI_0Oper *zero, + OptoReg::Name reg_second, OptoReg::Name reg_first, + OptoReg::Name reg_vec_second, OptoReg::Name reg_vec_first) { + loadConLReplicatedNodesTuple nodes; + + const bool large_constant_pool = true; // TODO: PPC port C->cfg()->_consts_size > 4000; + if (large_constant_pool) { + // Create new nodes. + loadConL_hiNode *m1 = new loadConL_hiNode(); + loadConL_loNode *m2 = new loadConL_loNode(); + mtvsrdNode *m3 = new mtvsrdNode(); + xxspltdNode *m4 = new xxspltdNode(); + + // inputs for new nodes + m1->add_req(NULL, toc); + m2->add_req(NULL, m1); + m3->add_req(NULL, m2); + m4->add_req(NULL, m3); + + // operands for new nodes + m1->_opnds[0] = new iRegLdstOper(); // dst + m1->_opnds[1] = immSrc; // src + m1->_opnds[2] = new iRegPdstOper(); // toc + + m2->_opnds[0] = new iRegLdstOper(); // dst + m2->_opnds[1] = immSrc; // src + m2->_opnds[2] = new iRegLdstOper(); // base + + m3->_opnds[0] = new vecXOper(); // dst + m3->_opnds[1] = new iRegLdstOper(); // src + + m4->_opnds[0] = new vecXOper(); // dst + m4->_opnds[1] = new vecXOper(); // src + m4->_opnds[2] = zero; + + // Initialize ins_attrib TOC fields. + m1->_const_toc_offset = -1; + m2->_const_toc_offset_hi_node = m1; + + // Initialize ins_attrib instruction offset. + m1->_cbuf_insts_offset = -1; + + // register allocation for new nodes + ra_->set_pair(m1->_idx, reg_second, reg_first); + ra_->set_pair(m2->_idx, reg_second, reg_first); + ra_->set1(m3->_idx, reg_second); + ra_->set2(m3->_idx, reg_vec_first); + ra_->set_pair(m4->_idx, reg_vec_second, reg_vec_first); + + // Create result. + nodes._large_hi = m1; + nodes._large_lo = m2; + nodes._moved = m3; + nodes._replicated = m4; + nodes._small = NULL; + nodes._last = nodes._replicated; + assert(m2->bottom_type()->isa_long(), "must be long"); + } else { + loadConLNode *m2 = new loadConLNode(); + mtvsrdNode *m3 = new mtvsrdNode(); + xxspltdNode *m4 = new xxspltdNode(); + + // inputs for new nodes + m2->add_req(NULL, toc); + + // operands for new nodes + m2->_opnds[0] = new iRegLdstOper(); // dst + m2->_opnds[1] = immSrc; // src + m2->_opnds[2] = new iRegPdstOper(); // toc + + m3->_opnds[0] = new vecXOper(); // dst + m3->_opnds[1] = new iRegLdstOper(); // src + + m4->_opnds[0] = new vecXOper(); // dst + m4->_opnds[1] = new vecXOper(); // src + m4->_opnds[2] = zero; + + // Initialize ins_attrib instruction offset. + m2->_cbuf_insts_offset = -1; + ra_->set1(m3->_idx, reg_second); + ra_->set2(m3->_idx, reg_vec_first); + ra_->set_pair(m4->_idx, reg_vec_second, reg_vec_first); + + // register allocation for new nodes + ra_->set_pair(m2->_idx, reg_second, reg_first); + + // Create result. + nodes._large_hi = NULL; + nodes._large_lo = NULL; + nodes._small = m2; + nodes._moved = m3; + nodes._replicated = m4; + nodes._last = nodes._replicated; + assert(m2->bottom_type()->isa_long(), "must be long"); + } + + return nodes; +} + %} // source encode %{ @@ -3212,6 +3525,27 @@ encode %{ assert(loadConLNodes._last->bottom_type()->isa_long(), "must be long"); %} + enc_class postalloc_expand_load_replF_constant_vsx(vecX dst, immF src, iRegLdst toc) %{ + // Create new nodes. + + // Make an operand with the bit pattern to load as float. + immLOper *op_repl = new immLOper((jlong)replicate_immF(op_src->constantF())); + immI_0Oper *op_zero = new immI_0Oper(0); + + loadConLReplicatedNodesTuple loadConLNodes = + loadConLReplicatedNodesTuple_create(C, ra_, n_toc, op_repl, op_dst, op_zero, + OptoReg::Name(R20_H_num), OptoReg::Name(R20_num), + OptoReg::Name(VSR11_num), OptoReg::Name(VSR10_num)); + + // Push new nodes. + if (loadConLNodes._large_hi) { nodes->push(loadConLNodes._large_hi); } + if (loadConLNodes._large_lo) { nodes->push(loadConLNodes._large_lo); } + if (loadConLNodes._moved) { nodes->push(loadConLNodes._moved); } + if (loadConLNodes._last) { nodes->push(loadConLNodes._last); } + + assert(nodes->length() >= 1, "must have created at least 1 node"); + %} + // This enc_class is needed so that scheduler gets proper // input mapping for latency computation. enc_class enc_poll(immI dst, iRegLdst poll) %{ @@ -3840,6 +4174,14 @@ ins_attrib ins_field_load_ic_node(0); // // Formats are generated automatically for constants and base registers. +operand vecX() %{ + constraint(ALLOC_IN_RC(vs_reg)); + match(VecX); + + format %{ %} + interface(REG_INTER); +%} + //----------Simple Operands---------------------------------------------------- // Immediate Operands @@ -5372,6 +5714,20 @@ instruct loadV8(iRegLdst dst, memoryAlg4 mem) %{ ins_pipe(pipe_class_memory); %} +// Load Aligned Packed Byte +instruct loadV16(vecX dst, indirect mem) %{ + predicate(n->as_LoadVector()->memory_size() == 16); + match(Set dst (LoadVector mem)); + ins_cost(MEMORY_REF_COST); + + format %{ "LXVD2X $dst, $mem \t// load 16-byte Vector" %} + size(4); + ins_encode %{ + __ lxvd2x($dst$$VectorSRegister, $mem$$Register); + %} + ins_pipe(pipe_class_default); +%} + // Load Range, range = array length (=jint) instruct loadRange(iRegIdst dst, memory mem) %{ match(Set dst (LoadRange mem)); @@ -6368,6 +6724,20 @@ instruct storeA8B(memoryAlg4 mem, iRegLsrc src) %{ ins_pipe(pipe_class_memory); %} +// Store Packed Byte long register to memory +instruct storeV16(indirect mem, vecX src) %{ + predicate(n->as_StoreVector()->memory_size() == 16); + match(Set mem (StoreVector mem src)); + ins_cost(MEMORY_REF_COST); + + format %{ "STXVD2X $mem, $src \t// store 16-byte Vector" %} + size(4); + ins_encode %{ + __ stxvd2x($src$$VectorSRegister, $mem$$Register); + %} + ins_pipe(pipe_class_default); +%} + // Store Compressed Oop instruct storeN(memory dst, iRegN_P2N src) %{ match(Set dst (StoreN dst src)); @@ -13239,6 +13609,26 @@ instruct storeS_reversed(iRegIsrc src, indirect mem) %{ ins_pipe(pipe_class_default); %} +instruct mtvsrwz(vecX temp1, iRegIsrc src) %{ + effect(DEF temp1, USE src); + + size(4); + ins_encode %{ + __ mtvsrwz($temp1$$VectorSRegister, $src$$Register); + %} + ins_pipe(pipe_class_default); +%} + +instruct xxspltw(vecX dst, vecX src, immI8 imm1) %{ + effect(DEF dst, USE src, USE imm1); + + size(4); + ins_encode %{ + __ xxspltw($dst$$VectorSRegister, $src$$VectorSRegister, $imm1$$constant); + %} + ins_pipe(pipe_class_default); +%} + //---------- Replicate Vector Instructions ------------------------------------ // Insrdi does replicate if src == dst. @@ -13318,6 +13708,46 @@ instruct repl8B_immIminus1(iRegLdst dst, immI_minus1 src) %{ ins_pipe(pipe_class_default); %} +instruct repl16B_reg_Ex(vecX dst, iRegIsrc src) %{ + match(Set dst (ReplicateB src)); + predicate(n->as_Vector()->length() == 16); + + expand %{ + iRegLdst tmpL; + vecX tmpV; + immI8 imm1 %{ (int) 1 %} + moveReg(tmpL, src); + repl56(tmpL); + repl48(tmpL); + mtvsrwz(tmpV, tmpL); + xxspltw(dst, tmpV, imm1); + %} +%} + +instruct repl16B_immI0(vecX dst, immI_0 zero) %{ + match(Set dst (ReplicateB zero)); + predicate(n->as_Vector()->length() == 16); + + format %{ "XXLXOR $dst, $zero \t// replicate16B" %} + size(4); + ins_encode %{ + __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister); + %} + ins_pipe(pipe_class_default); +%} + +instruct repl16B_immIminus1(vecX dst, immI_minus1 src) %{ + match(Set dst (ReplicateB src)); + predicate(n->as_Vector()->length() == 16); + + format %{ "XXLEQV $dst, $src \t// replicate16B" %} + size(4); + ins_encode %{ + __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister); + %} + ins_pipe(pipe_class_default); +%} + instruct repl4S_reg_Ex(iRegLdst dst, iRegIsrc src) %{ match(Set dst (ReplicateS src)); predicate(n->as_Vector()->length() == 4); @@ -13352,6 +13782,46 @@ instruct repl4S_immIminus1(iRegLdst dst, immI_minus1 src) %{ ins_pipe(pipe_class_default); %} +instruct repl8S_reg_Ex(vecX dst, iRegIsrc src) %{ + match(Set dst (ReplicateS src)); + predicate(n->as_Vector()->length() == 8); + + expand %{ + iRegLdst tmpL; + vecX tmpV; + immI8 zero %{ (int) 0 %} + moveReg(tmpL, src); + repl48(tmpL); + repl32(tmpL); + mtvsrd(tmpV, tmpL); + xxpermdi(dst, tmpV, tmpV, zero); + %} +%} + +instruct repl8S_immI0(vecX dst, immI_0 zero) %{ + match(Set dst (ReplicateS zero)); + predicate(n->as_Vector()->length() == 8); + + format %{ "XXLXOR $dst, $zero \t// replicate8S" %} + size(4); + ins_encode %{ + __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister); + %} + ins_pipe(pipe_class_default); +%} + +instruct repl8S_immIminus1(vecX dst, immI_minus1 src) %{ + match(Set dst (ReplicateS src)); + predicate(n->as_Vector()->length() == 8); + + format %{ "XXLEQV $dst, $src \t// replicate16B" %} + size(4); + ins_encode %{ + __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister); + %} + ins_pipe(pipe_class_default); +%} + instruct repl2I_reg_Ex(iRegLdst dst, iRegIsrc src) %{ match(Set dst (ReplicateI src)); predicate(n->as_Vector()->length() == 2); @@ -13386,6 +13856,46 @@ instruct repl2I_immIminus1(iRegLdst dst, immI_minus1 src) %{ ins_pipe(pipe_class_default); %} +instruct repl4I_reg_Ex(vecX dst, iRegIsrc src) %{ + match(Set dst (ReplicateI src)); + predicate(n->as_Vector()->length() == 4); + ins_cost(2 * DEFAULT_COST); + + expand %{ + iRegLdst tmpL; + vecX tmpV; + immI8 zero %{ (int) 0 %} + moveReg(tmpL, src); + repl32(tmpL); + mtvsrd(tmpV, tmpL); + xxpermdi(dst, tmpV, tmpV, zero); + %} +%} + +instruct repl4I_immI0(vecX dst, immI_0 zero) %{ + match(Set dst (ReplicateI zero)); + predicate(n->as_Vector()->length() == 4); + + format %{ "XXLXOR $dst, $zero \t// replicate4I" %} + size(4); + ins_encode %{ + __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister); + %} + ins_pipe(pipe_class_default); +%} + +instruct repl4I_immIminus1(vecX dst, immI_minus1 src) %{ + match(Set dst (ReplicateI src)); + predicate(n->as_Vector()->length() == 4); + + format %{ "XXLEQV $dst, $dst, $dst \t// replicate4I" %} + size(4); + ins_encode %{ + __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister); + %} + ins_pipe(pipe_class_default); +%} + // Move float to int register via stack, replicate. instruct repl2F_reg_Ex(iRegLdst dst, regF src) %{ match(Set dst (ReplicateF src)); @@ -13484,6 +13994,154 @@ instruct overflowMulL_reg_reg(flagsRegCR0 cr0, iRegLsrc op1, iRegLsrc op2) %{ %} +instruct repl4F_reg_Ex(vecX dst, regF src) %{ + match(Set dst (ReplicateF src)); + predicate(n->as_Vector()->length() == 4); + ins_cost(2 * MEMORY_REF_COST + DEFAULT_COST); + expand %{ + stackSlotL tmpS; + iRegIdst tmpI; + iRegLdst tmpL; + vecX tmpV; + immI8 zero %{ (int) 0 %} + + moveF2I_reg_stack(tmpS, src); // Move float to stack. + moveF2I_stack_reg(tmpI, tmpS); // Move stack to int reg. + moveReg(tmpL, tmpI); // Move int to long reg. + repl32(tmpL); // Replicate bitpattern. + mtvsrd(tmpV, tmpL); + xxpermdi(dst, tmpV, tmpV, zero); + %} +%} + +instruct repl4F_immF_Ex(vecX dst, immF src) %{ + match(Set dst (ReplicateF src)); + predicate(n->as_Vector()->length() == 4); + ins_cost(10 * DEFAULT_COST); + + postalloc_expand( postalloc_expand_load_replF_constant_vsx(dst, src, constanttablebase) ); +%} + +instruct repl4F_immF0(vecX dst, immF_0 zero) %{ + match(Set dst (ReplicateF zero)); + predicate(n->as_Vector()->length() == 4); + + format %{ "XXLXOR $dst, $zero \t// replicate4F" %} + ins_encode %{ + __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister); + %} + ins_pipe(pipe_class_default); +%} + +instruct repl2D_reg_Ex(vecX dst, regD src) %{ + match(Set dst (ReplicateD src)); + predicate(n->as_Vector()->length() == 2); + expand %{ + stackSlotL tmpS; + iRegLdst tmpL; + iRegLdst tmp; + vecX tmpV; + immI8 zero %{ (int) 0 %} + moveD2L_reg_stack(tmpS, src); + moveD2L_stack_reg(tmpL, tmpS); + mtvsrd(tmpV, tmpL); + xxpermdi(dst, tmpV, tmpV, zero); + %} +%} + +instruct repl2D_immI0(vecX dst, immI_0 zero) %{ + match(Set dst (ReplicateD zero)); + predicate(n->as_Vector()->length() == 2); + + format %{ "XXLXOR $dst, $zero \t// replicate2D" %} + size(4); + ins_encode %{ + __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister); + %} + ins_pipe(pipe_class_default); +%} + +instruct repl2D_immIminus1(vecX dst, immI_minus1 src) %{ + match(Set dst (ReplicateD src)); + predicate(n->as_Vector()->length() == 2); + + format %{ "XXLEQV $dst, $src \t// replicate16B" %} + size(4); + ins_encode %{ + __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister); + %} + ins_pipe(pipe_class_default); +%} + +instruct mtvsrd(vecX dst, iRegLsrc src) %{ + predicate(false); + effect(DEF dst, USE src); + + format %{ "MTVSRD $dst, $src \t// Move to 16-byte register"%} + size(4); + ins_encode %{ + __ mtvsrd($dst$$VectorSRegister, $src$$Register); + %} + ins_pipe(pipe_class_default); +%} + +instruct xxspltd(vecX dst, vecX src, immI8 zero) %{ + effect(DEF dst, USE src, USE zero); + + format %{ "XXSPLATD $dst, $src, $zero \t// Permute 16-byte register"%} + size(4); + ins_encode %{ + __ xxpermdi($dst$$VectorSRegister, $src$$VectorSRegister, $src$$VectorSRegister, $zero$$constant); + %} + ins_pipe(pipe_class_default); +%} + +instruct xxpermdi(vecX dst, vecX src1, vecX src2, immI8 zero) %{ + effect(DEF dst, USE src1, USE src2, USE zero); + + format %{ "XXPERMDI $dst, $src1, $src2, $zero \t// Permute 16-byte register"%} + size(4); + ins_encode %{ + __ xxpermdi($dst$$VectorSRegister, $src1$$VectorSRegister, $src2$$VectorSRegister, $zero$$constant); + %} + ins_pipe(pipe_class_default); +%} + +instruct repl2L_reg_Ex(vecX dst, iRegLsrc src) %{ + match(Set dst (ReplicateL src)); + predicate(n->as_Vector()->length() == 2); + expand %{ + vecX tmpV; + immI8 zero %{ (int) 0 %} + mtvsrd(tmpV, src); + xxpermdi(dst, tmpV, tmpV, zero); + %} +%} + +instruct repl2L_immI0(vecX dst, immI_0 zero) %{ + match(Set dst (ReplicateL zero)); + predicate(n->as_Vector()->length() == 2); + + format %{ "XXLXOR $dst, $zero \t// replicate2L" %} + size(4); + ins_encode %{ + __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister); + %} + ins_pipe(pipe_class_default); +%} + +instruct repl2L_immIminus1(vecX dst, immI_minus1 src) %{ + match(Set dst (ReplicateL src)); + predicate(n->as_Vector()->length() == 2); + + format %{ "XXLEQV $dst, $src \t// replicate16B" %} + size(4); + ins_encode %{ + __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister); + %} + ins_pipe(pipe_class_default); +%} + // ============================================================================ // Safepoint Instruction diff --git a/src/hotspot/cpu/ppc/register_definitions_ppc.cpp b/src/hotspot/cpu/ppc/register_definitions_ppc.cpp index 2a2d968e44d..d5a064b169f 100644 --- a/src/hotspot/cpu/ppc/register_definitions_ppc.cpp +++ b/src/hotspot/cpu/ppc/register_definitions_ppc.cpp @@ -31,3 +31,5 @@ REGISTER_DEFINITION(Register, noreg); REGISTER_DEFINITION(FloatRegister, fnoreg); + +REGISTER_DEFINITION(VectorSRegister, vsnoreg); diff --git a/src/hotspot/cpu/ppc/register_ppc.hpp b/src/hotspot/cpu/ppc/register_ppc.hpp index c554f88619d..af516ce2d8f 100644 --- a/src/hotspot/cpu/ppc/register_ppc.hpp +++ b/src/hotspot/cpu/ppc/register_ppc.hpp @@ -677,7 +677,7 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl { * 2 // register halves + ConditionRegisterImpl::number_of_registers // condition code registers + SpecialRegisterImpl::number_of_registers // special registers - + VectorRegisterImpl::number_of_registers // VSX registers + + VectorSRegisterImpl::number_of_registers // VSX registers }; static const int max_gpr; diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 20a1a963abc..4b879905afa 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -479,8 +479,8 @@ void RegisterSaver::restore_result_registers(MacroAssembler* masm, int frame_siz // Is vector's size (in bytes) bigger than a size saved by default? bool SharedRuntime::is_wide_vector(int size) { - // Note, MaxVectorSize == 8 on PPC64. - assert(size <= 8, "%d bytes vectors are not supported", size); + // Note, MaxVectorSize == 8/16 on PPC64. + assert(size <= (SuperwordUseVSX ? 16 : 8), "%d bytes vectors are not supported", size); return size > 8; } @@ -2234,9 +2234,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ release(); // TODO: PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size"); __ stw(R0, thread_(thread_state)); - if (UseMembar) { - __ fence(); - } // The JNI call @@ -2393,9 +2390,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ release(); // TODO: PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size"); __ stw(R0, thread_(thread_state)); - if (UseMembar) { - __ fence(); - } __ bind(after_transition); // Reguard any pages if necessary. diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index 2eb4937a6fa..16cb6149f77 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -2667,7 +2667,7 @@ class StubGenerator: public StubCodeGenerator { return start; } - // Arguments for generated stub (little endian only): + // Arguments for generated stub: // R3_ARG1 - source byte array address // R4_ARG2 - destination byte array address // R5_ARG3 - round key array @@ -2686,7 +2686,6 @@ class StubGenerator: public StubCodeGenerator { Register keylen = R8; Register temp = R9; Register keypos = R10; - Register hex = R11; Register fifteen = R12; VectorRegister vRet = VR0; @@ -2706,164 +2705,170 @@ class StubGenerator: public StubCodeGenerator { VectorRegister vTmp3 = VR11; VectorRegister vTmp4 = VR12; - VectorRegister vLow = VR13; - VectorRegister vHigh = VR14; - - __ li (hex, 16); __ li (fifteen, 15); - __ vspltisb (fSplt, 0x0f); // load unaligned from[0-15] to vsRet __ lvx (vRet, from); __ lvx (vTmp1, fifteen, from); __ lvsl (fromPerm, from); +#ifdef VM_LITTLE_ENDIAN + __ vspltisb (fSplt, 0x0f); __ vxor (fromPerm, fromPerm, fSplt); +#endif __ vperm (vRet, vRet, vTmp1, fromPerm); // load keylen (44 or 52 or 60) __ lwz (keylen, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT), key); // to load keys - __ lvsr (keyPerm, key); - __ vxor (vTmp2, vTmp2, vTmp2); + __ load_perm (keyPerm, key); +#ifdef VM_LITTLE_ENDIAN __ vspltisb (vTmp2, -16); __ vrld (keyPerm, keyPerm, vTmp2); __ vrld (keyPerm, keyPerm, vTmp2); __ vsldoi (keyPerm, keyPerm, keyPerm, 8); +#endif - // load the 1st round key to vKey1 - __ li (keypos, 0); + // load the 1st round key to vTmp1 + __ lvx (vTmp1, key); + __ li (keypos, 16); __ lvx (vKey1, keypos, key); - __ addi (keypos, keypos, 16); - __ lvx (vTmp1, keypos, key); - __ vperm (vKey1, vTmp1, vKey1, keyPerm); + __ vec_perm (vTmp1, vKey1, keyPerm); // 1st round - __ vxor (vRet, vRet, vKey1); + __ vxor (vRet, vRet, vTmp1); // load the 2nd round key to vKey1 - __ addi (keypos, keypos, 16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + __ li (keypos, 32); + __ lvx (vKey2, keypos, key); + __ vec_perm (vKey1, vKey2, keyPerm); // load the 3rd round key to vKey2 - __ addi (keypos, keypos, 16); - __ lvx (vTmp1, keypos, key); - __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + __ li (keypos, 48); + __ lvx (vKey3, keypos, key); + __ vec_perm (vKey2, vKey3, keyPerm); // load the 4th round key to vKey3 - __ addi (keypos, keypos, 16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey3, vTmp2, vTmp1, keyPerm); + __ li (keypos, 64); + __ lvx (vKey4, keypos, key); + __ vec_perm (vKey3, vKey4, keyPerm); // load the 5th round key to vKey4 - __ addi (keypos, keypos, 16); + __ li (keypos, 80); __ lvx (vTmp1, keypos, key); - __ vperm (vKey4, vTmp1, vTmp2, keyPerm); + __ vec_perm (vKey4, vTmp1, keyPerm); // 2nd - 5th rounds - __ vcipher (vRet, vRet, vKey1); - __ vcipher (vRet, vRet, vKey2); - __ vcipher (vRet, vRet, vKey3); - __ vcipher (vRet, vRet, vKey4); + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + __ vcipher (vRet, vRet, vKey3); + __ vcipher (vRet, vRet, vKey4); // load the 6th round key to vKey1 - __ addi (keypos, keypos, 16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + __ li (keypos, 96); + __ lvx (vKey2, keypos, key); + __ vec_perm (vKey1, vTmp1, vKey2, keyPerm); // load the 7th round key to vKey2 - __ addi (keypos, keypos, 16); - __ lvx (vTmp1, keypos, key); - __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + __ li (keypos, 112); + __ lvx (vKey3, keypos, key); + __ vec_perm (vKey2, vKey3, keyPerm); // load the 8th round key to vKey3 - __ addi (keypos, keypos, 16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey3, vTmp2, vTmp1, keyPerm); + __ li (keypos, 128); + __ lvx (vKey4, keypos, key); + __ vec_perm (vKey3, vKey4, keyPerm); // load the 9th round key to vKey4 - __ addi (keypos, keypos, 16); + __ li (keypos, 144); __ lvx (vTmp1, keypos, key); - __ vperm (vKey4, vTmp1, vTmp2, keyPerm); + __ vec_perm (vKey4, vTmp1, keyPerm); // 6th - 9th rounds - __ vcipher (vRet, vRet, vKey1); - __ vcipher (vRet, vRet, vKey2); - __ vcipher (vRet, vRet, vKey3); - __ vcipher (vRet, vRet, vKey4); + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + __ vcipher (vRet, vRet, vKey3); + __ vcipher (vRet, vRet, vKey4); // load the 10th round key to vKey1 - __ addi (keypos, keypos, 16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + __ li (keypos, 160); + __ lvx (vKey2, keypos, key); + __ vec_perm (vKey1, vTmp1, vKey2, keyPerm); // load the 11th round key to vKey2 - __ addi (keypos, keypos, 16); + __ li (keypos, 176); __ lvx (vTmp1, keypos, key); - __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + __ vec_perm (vKey2, vTmp1, keyPerm); // if all round keys are loaded, skip next 4 rounds __ cmpwi (CCR0, keylen, 44); __ beq (CCR0, L_doLast); // 10th - 11th rounds - __ vcipher (vRet, vRet, vKey1); - __ vcipher (vRet, vRet, vKey2); + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); // load the 12th round key to vKey1 - __ addi (keypos, keypos, 16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + __ li (keypos, 192); + __ lvx (vKey2, keypos, key); + __ vec_perm (vKey1, vTmp1, vKey2, keyPerm); // load the 13th round key to vKey2 - __ addi (keypos, keypos, 16); + __ li (keypos, 208); __ lvx (vTmp1, keypos, key); - __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + __ vec_perm (vKey2, vTmp1, keyPerm); // if all round keys are loaded, skip next 2 rounds __ cmpwi (CCR0, keylen, 52); __ beq (CCR0, L_doLast); // 12th - 13th rounds - __ vcipher (vRet, vRet, vKey1); - __ vcipher (vRet, vRet, vKey2); + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); // load the 14th round key to vKey1 - __ addi (keypos, keypos, 16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + __ li (keypos, 224); + __ lvx (vKey2, keypos, key); + __ vec_perm (vKey1, vTmp1, vKey2, keyPerm); // load the 15th round key to vKey2 - __ addi (keypos, keypos, 16); + __ li (keypos, 240); __ lvx (vTmp1, keypos, key); - __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + __ vec_perm (vKey2, vTmp1, keyPerm); __ bind(L_doLast); // last two rounds - __ vcipher (vRet, vRet, vKey1); - __ vcipherlast (vRet, vRet, vKey2); + __ vcipher (vRet, vRet, vKey1); + __ vcipherlast (vRet, vRet, vKey2); - __ neg (temp, to); - __ lvsr (toPerm, temp); - __ vspltisb (vTmp2, -1); - __ vxor (vTmp1, vTmp1, vTmp1); - __ vperm (vTmp2, vTmp2, vTmp1, toPerm); - __ vxor (toPerm, toPerm, fSplt); + // store result (unaligned) +#ifdef VM_LITTLE_ENDIAN + __ lvsl (toPerm, to); +#else + __ lvsr (toPerm, to); +#endif + __ vspltisb (vTmp3, -1); + __ vspltisb (vTmp4, 0); __ lvx (vTmp1, to); - __ vperm (vRet, vRet, vRet, toPerm); - __ vsel (vTmp1, vTmp1, vRet, vTmp2); - __ lvx (vTmp4, fifteen, to); + __ lvx (vTmp2, fifteen, to); +#ifdef VM_LITTLE_ENDIAN + __ vperm (vTmp3, vTmp3, vTmp4, toPerm); // generate select mask + __ vxor (toPerm, toPerm, fSplt); // swap bytes +#else + __ vperm (vTmp3, vTmp4, vTmp3, toPerm); // generate select mask +#endif + __ vperm (vTmp4, vRet, vRet, toPerm); // rotate data + __ vsel (vTmp2, vTmp4, vTmp2, vTmp3); + __ vsel (vTmp1, vTmp1, vTmp4, vTmp3); + __ stvx (vTmp2, fifteen, to); // store this one first (may alias) __ stvx (vTmp1, to); - __ vsel (vRet, vRet, vTmp4, vTmp2); - __ stvx (vRet, fifteen, to); __ blr(); return start; } - // Arguments for generated stub (little endian only): + // Arguments for generated stub: // R3_ARG1 - source byte array address // R4_ARG2 - destination byte array address // R5_ARG3 - K (key) in little endian int array @@ -2885,7 +2890,6 @@ class StubGenerator: public StubCodeGenerator { Register keylen = R8; Register temp = R9; Register keypos = R10; - Register hex = R11; Register fifteen = R12; VectorRegister vRet = VR0; @@ -2906,30 +2910,30 @@ class StubGenerator: public StubCodeGenerator { VectorRegister vTmp3 = VR12; VectorRegister vTmp4 = VR13; - VectorRegister vLow = VR14; - VectorRegister vHigh = VR15; - - __ li (hex, 16); __ li (fifteen, 15); - __ vspltisb (fSplt, 0x0f); // load unaligned from[0-15] to vsRet __ lvx (vRet, from); __ lvx (vTmp1, fifteen, from); __ lvsl (fromPerm, from); +#ifdef VM_LITTLE_ENDIAN + __ vspltisb (fSplt, 0x0f); __ vxor (fromPerm, fromPerm, fSplt); +#endif __ vperm (vRet, vRet, vTmp1, fromPerm); // align [and byte swap in LE] // load keylen (44 or 52 or 60) __ lwz (keylen, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT), key); // to load keys - __ lvsr (keyPerm, key); + __ load_perm (keyPerm, key); +#ifdef VM_LITTLE_ENDIAN __ vxor (vTmp2, vTmp2, vTmp2); __ vspltisb (vTmp2, -16); __ vrld (keyPerm, keyPerm, vTmp2); __ vrld (keyPerm, keyPerm, vTmp2); __ vsldoi (keyPerm, keyPerm, keyPerm, 8); +#endif __ cmpwi (CCR0, keylen, 44); __ beq (CCR0, L_do44); @@ -2937,32 +2941,32 @@ class StubGenerator: public StubCodeGenerator { __ cmpwi (CCR0, keylen, 52); __ beq (CCR0, L_do52); - // load the 15th round key to vKey11 + // load the 15th round key to vKey1 __ li (keypos, 240); + __ lvx (vKey1, keypos, key); + __ li (keypos, 224); + __ lvx (vKey2, keypos, key); + __ vec_perm (vKey1, vKey2, vKey1, keyPerm); + + // load the 14th round key to vKey2 + __ li (keypos, 208); + __ lvx (vKey3, keypos, key); + __ vec_perm (vKey2, vKey3, vKey2, keyPerm); + + // load the 13th round key to vKey3 + __ li (keypos, 192); + __ lvx (vKey4, keypos, key); + __ vec_perm (vKey3, vKey4, vKey3, keyPerm); + + // load the 12th round key to vKey4 + __ li (keypos, 176); + __ lvx (vKey5, keypos, key); + __ vec_perm (vKey4, vKey5, vKey4, keyPerm); + + // load the 11th round key to vKey5 + __ li (keypos, 160); __ lvx (vTmp1, keypos, key); - __ addi (keypos, keypos, -16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey1, vTmp1, vTmp2, keyPerm); - - // load the 14th round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp1, keypos, key); - __ vperm (vKey2, vTmp2, vTmp1, keyPerm); - - // load the 13th round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey3, vTmp1, vTmp2, keyPerm); - - // load the 12th round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp1, keypos, key); - __ vperm (vKey4, vTmp2, vTmp1, keyPerm); - - // load the 11th round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey5, vTmp1, vTmp2, keyPerm); + __ vec_perm (vKey5, vTmp1, vKey5, keyPerm); // 1st - 5th rounds __ vxor (vRet, vRet, vKey1); @@ -2975,22 +2979,22 @@ class StubGenerator: public StubCodeGenerator { __ bind (L_do52); - // load the 13th round key to vKey11 + // load the 13th round key to vKey1 __ li (keypos, 208); - __ lvx (vTmp1, keypos, key); - __ addi (keypos, keypos, -16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey1, vTmp1, vTmp2, keyPerm); + __ lvx (vKey1, keypos, key); + __ li (keypos, 192); + __ lvx (vKey2, keypos, key); + __ vec_perm (vKey1, vKey2, vKey1, keyPerm); - // load the 12th round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp1, keypos, key); - __ vperm (vKey2, vTmp2, vTmp1, keyPerm); + // load the 12th round key to vKey2 + __ li (keypos, 176); + __ lvx (vKey3, keypos, key); + __ vec_perm (vKey2, vKey3, vKey2, keyPerm); - // load the 11th round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey3, vTmp1, vTmp2, keyPerm); + // load the 11th round key to vKey3 + __ li (keypos, 160); + __ lvx (vTmp1, keypos, key); + __ vec_perm (vKey3, vTmp1, vKey3, keyPerm); // 1st - 3rd rounds __ vxor (vRet, vRet, vKey1); @@ -3001,42 +3005,42 @@ class StubGenerator: public StubCodeGenerator { __ bind (L_do44); - // load the 11th round key to vKey11 + // load the 11th round key to vKey1 __ li (keypos, 176); + __ lvx (vKey1, keypos, key); + __ li (keypos, 160); __ lvx (vTmp1, keypos, key); - __ addi (keypos, keypos, -16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey1, vTmp1, vTmp2, keyPerm); + __ vec_perm (vKey1, vTmp1, vKey1, keyPerm); // 1st round __ vxor (vRet, vRet, vKey1); __ bind (L_doLast); - // load the 10th round key to vKey10 - __ addi (keypos, keypos, -16); + // load the 10th round key to vKey1 + __ li (keypos, 144); + __ lvx (vKey2, keypos, key); + __ vec_perm (vKey1, vKey2, vTmp1, keyPerm); + + // load the 9th round key to vKey2 + __ li (keypos, 128); + __ lvx (vKey3, keypos, key); + __ vec_perm (vKey2, vKey3, vKey2, keyPerm); + + // load the 8th round key to vKey3 + __ li (keypos, 112); + __ lvx (vKey4, keypos, key); + __ vec_perm (vKey3, vKey4, vKey3, keyPerm); + + // load the 7th round key to vKey4 + __ li (keypos, 96); + __ lvx (vKey5, keypos, key); + __ vec_perm (vKey4, vKey5, vKey4, keyPerm); + + // load the 6th round key to vKey5 + __ li (keypos, 80); __ lvx (vTmp1, keypos, key); - __ vperm (vKey1, vTmp2, vTmp1, keyPerm); - - // load the 9th round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey2, vTmp1, vTmp2, keyPerm); - - // load the 8th round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp1, keypos, key); - __ vperm (vKey3, vTmp2, vTmp1, keyPerm); - - // load the 7th round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey4, vTmp1, vTmp2, keyPerm); - - // load the 6th round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp1, keypos, key); - __ vperm (vKey5, vTmp2, vTmp1, keyPerm); + __ vec_perm (vKey5, vTmp1, vKey5, keyPerm); // last 10th - 6th rounds __ vncipher (vRet, vRet, vKey1); @@ -3045,30 +3049,29 @@ class StubGenerator: public StubCodeGenerator { __ vncipher (vRet, vRet, vKey4); __ vncipher (vRet, vRet, vKey5); - // load the 5th round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey1, vTmp1, vTmp2, keyPerm); + // load the 5th round key to vKey1 + __ li (keypos, 64); + __ lvx (vKey2, keypos, key); + __ vec_perm (vKey1, vKey2, vTmp1, keyPerm); - // load the 4th round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp1, keypos, key); - __ vperm (vKey2, vTmp2, vTmp1, keyPerm); + // load the 4th round key to vKey2 + __ li (keypos, 48); + __ lvx (vKey3, keypos, key); + __ vec_perm (vKey2, vKey3, vKey2, keyPerm); - // load the 3rd round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey3, vTmp1, vTmp2, keyPerm); + // load the 3rd round key to vKey3 + __ li (keypos, 32); + __ lvx (vKey4, keypos, key); + __ vec_perm (vKey3, vKey4, vKey3, keyPerm); - // load the 2nd round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp1, keypos, key); - __ vperm (vKey4, vTmp2, vTmp1, keyPerm); + // load the 2nd round key to vKey4 + __ li (keypos, 16); + __ lvx (vKey5, keypos, key); + __ vec_perm (vKey4, vKey5, vKey4, keyPerm); - // load the 1st round key to vKey10 - __ addi (keypos, keypos, -16); - __ lvx (vTmp2, keypos, key); - __ vperm (vKey5, vTmp1, vTmp2, keyPerm); + // load the 1st round key to vKey5 + __ lvx (vTmp1, key); + __ vec_perm (vKey5, vTmp1, vKey5, keyPerm); // last 5th - 1th rounds __ vncipher (vRet, vRet, vKey1); @@ -3077,24 +3080,54 @@ class StubGenerator: public StubCodeGenerator { __ vncipher (vRet, vRet, vKey4); __ vncipherlast (vRet, vRet, vKey5); - __ neg (temp, to); - __ lvsr (toPerm, temp); - __ vspltisb (vTmp2, -1); - __ vxor (vTmp1, vTmp1, vTmp1); - __ vperm (vTmp2, vTmp2, vTmp1, toPerm); - __ vxor (toPerm, toPerm, fSplt); + // store result (unaligned) +#ifdef VM_LITTLE_ENDIAN + __ lvsl (toPerm, to); +#else + __ lvsr (toPerm, to); +#endif + __ vspltisb (vTmp3, -1); + __ vspltisb (vTmp4, 0); __ lvx (vTmp1, to); - __ vperm (vRet, vRet, vRet, toPerm); - __ vsel (vTmp1, vTmp1, vRet, vTmp2); - __ lvx (vTmp4, fifteen, to); + __ lvx (vTmp2, fifteen, to); +#ifdef VM_LITTLE_ENDIAN + __ vperm (vTmp3, vTmp3, vTmp4, toPerm); // generate select mask + __ vxor (toPerm, toPerm, fSplt); // swap bytes +#else + __ vperm (vTmp3, vTmp4, vTmp3, toPerm); // generate select mask +#endif + __ vperm (vTmp4, vRet, vRet, toPerm); // rotate data + __ vsel (vTmp2, vTmp4, vTmp2, vTmp3); + __ vsel (vTmp1, vTmp1, vTmp4, vTmp3); + __ stvx (vTmp2, fifteen, to); // store this one first (may alias) __ stvx (vTmp1, to); - __ vsel (vRet, vRet, vTmp4, vTmp2); - __ stvx (vRet, fifteen, to); __ blr(); return start; } + address generate_sha256_implCompress(bool multi_block, const char *name) { + assert(UseSHA, "need SHA instructions"); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ function_entry(); + + __ sha256 (multi_block); + + __ blr(); + return start; + } + + address generate_sha512_implCompress(bool multi_block, const char *name) { + assert(UseSHA, "need SHA instructions"); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ function_entry(); + + __ sha512 (multi_block); + + __ blr(); + return start; + } + void generate_arraycopy_stubs() { // Note: the disjoint stubs must be generated first, some of // the conjoint stubs use them. @@ -3306,6 +3339,267 @@ class StubGenerator: public StubCodeGenerator { BLOCK_COMMENT("} Stub body"); } + /** + * Arguments: + * + * Input: + * R3_ARG1 - out address + * R4_ARG2 - in address + * R5_ARG3 - offset + * R6_ARG4 - len + * R7_ARG5 - k + * Output: + * R3_RET - carry + */ + address generate_mulAdd() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "mulAdd"); + + address start = __ function_entry(); + + // C2 does not sign extend signed parameters to full 64 bits registers: + __ rldic (R5_ARG3, R5_ARG3, 2, 32); // always positive + __ clrldi(R6_ARG4, R6_ARG4, 32); // force zero bits on higher word + __ clrldi(R7_ARG5, R7_ARG5, 32); // force zero bits on higher word + + __ muladd(R3_ARG1, R4_ARG2, R5_ARG3, R6_ARG4, R7_ARG5, R8, R9, R10); + + // Moves output carry to return register + __ mr (R3_RET, R10); + + __ blr(); + + return start; + } + + /** + * Arguments: + * + * Input: + * R3_ARG1 - in address + * R4_ARG2 - in length + * R5_ARG3 - out address + * R6_ARG4 - out length + */ + address generate_squareToLen() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "squareToLen"); + + address start = __ function_entry(); + + // args - higher word is cleaned (unsignedly) due to int to long casting + const Register in = R3_ARG1; + const Register in_len = R4_ARG2; + __ clrldi(in_len, in_len, 32); + const Register out = R5_ARG3; + const Register out_len = R6_ARG4; + __ clrldi(out_len, out_len, 32); + + // output + const Register ret = R3_RET; + + // temporaries + const Register lplw_s = R7; + const Register in_aux = R8; + const Register out_aux = R9; + const Register piece = R10; + const Register product = R14; + const Register lplw = R15; + const Register i_minus1 = R16; + const Register carry = R17; + const Register offset = R18; + const Register off_aux = R19; + const Register t = R20; + const Register mlen = R21; + const Register len = R22; + const Register a = R23; + const Register b = R24; + const Register i = R25; + const Register c = R26; + const Register cs = R27; + + // Labels + Label SKIP_LSHIFT, SKIP_DIAGONAL_SUM, SKIP_ADDONE, SKIP_MULADD, SKIP_LOOP_SQUARE; + Label LOOP_LSHIFT, LOOP_DIAGONAL_SUM, LOOP_ADDONE, LOOP_MULADD, LOOP_SQUARE; + + // Save non-volatile regs (frameless). + int current_offs = -8; + __ std(R28, current_offs, R1_SP); current_offs -= 8; + __ std(R27, current_offs, R1_SP); current_offs -= 8; + __ std(R26, current_offs, R1_SP); current_offs -= 8; + __ std(R25, current_offs, R1_SP); current_offs -= 8; + __ std(R24, current_offs, R1_SP); current_offs -= 8; + __ std(R23, current_offs, R1_SP); current_offs -= 8; + __ std(R22, current_offs, R1_SP); current_offs -= 8; + __ std(R21, current_offs, R1_SP); current_offs -= 8; + __ std(R20, current_offs, R1_SP); current_offs -= 8; + __ std(R19, current_offs, R1_SP); current_offs -= 8; + __ std(R18, current_offs, R1_SP); current_offs -= 8; + __ std(R17, current_offs, R1_SP); current_offs -= 8; + __ std(R16, current_offs, R1_SP); current_offs -= 8; + __ std(R15, current_offs, R1_SP); current_offs -= 8; + __ std(R14, current_offs, R1_SP); + + // Store the squares, right shifted one bit (i.e., divided by 2) + __ subi (out_aux, out, 8); + __ subi (in_aux, in, 4); + __ cmpwi (CCR0, in_len, 0); + // Initialize lplw outside of the loop + __ xorr (lplw, lplw, lplw); + __ ble (CCR0, SKIP_LOOP_SQUARE); // in_len <= 0 + __ mtctr (in_len); + + __ bind(LOOP_SQUARE); + __ lwzu (piece, 4, in_aux); + __ mulld (product, piece, piece); + // shift left 63 bits and only keep the MSB + __ rldic (lplw_s, lplw, 63, 0); + __ mr (lplw, product); + // shift right 1 bit without sign extension + __ srdi (product, product, 1); + // join them to the same register and store it + __ orr (product, lplw_s, product); +#ifdef VM_LITTLE_ENDIAN + // Swap low and high words for little endian + __ rldicl (product, product, 32, 0); +#endif + __ stdu (product, 8, out_aux); + __ bdnz (LOOP_SQUARE); + + __ bind(SKIP_LOOP_SQUARE); + + // Add in off-diagonal sums + __ cmpwi (CCR0, in_len, 0); + __ ble (CCR0, SKIP_DIAGONAL_SUM); + // Avoid CTR usage here in order to use it at mulAdd + __ subi (i_minus1, in_len, 1); + __ li (offset, 4); + + __ bind(LOOP_DIAGONAL_SUM); + + __ sldi (off_aux, out_len, 2); + __ sub (off_aux, off_aux, offset); + + __ mr (len, i_minus1); + __ sldi (mlen, i_minus1, 2); + __ lwzx (t, in, mlen); + + __ muladd (out, in, off_aux, len, t, a, b, carry); + + // begin + // off_aux = out_len*4 - 4 - mlen - offset*4 - 4; + __ addi (mlen, mlen, 4); + __ sldi (a, out_len, 2); + __ subi (a, a, 4); + __ sub (a, a, mlen); + __ subi (off_aux, offset, 4); + __ sub (off_aux, a, off_aux); + + __ lwzx (b, off_aux, out); + __ add (b, b, carry); + __ stwx (b, off_aux, out); + + // if (((uint64_t)s >> 32) != 0) { + __ srdi_ (a, b, 32); + __ beq (CCR0, SKIP_ADDONE); + + // while (--mlen >= 0) { + __ bind(LOOP_ADDONE); + __ subi (mlen, mlen, 4); + __ cmpwi (CCR0, mlen, 0); + __ beq (CCR0, SKIP_ADDONE); + + // if (--offset_aux < 0) { // Carry out of number + __ subi (off_aux, off_aux, 4); + __ cmpwi (CCR0, off_aux, 0); + __ blt (CCR0, SKIP_ADDONE); + + // } else { + __ lwzx (b, off_aux, out); + __ addi (b, b, 1); + __ stwx (b, off_aux, out); + __ cmpwi (CCR0, b, 0); + __ bne (CCR0, SKIP_ADDONE); + __ b (LOOP_ADDONE); + + __ bind(SKIP_ADDONE); + // } } } end + + __ addi (offset, offset, 8); + __ subi (i_minus1, i_minus1, 1); + __ cmpwi (CCR0, i_minus1, 0); + __ bge (CCR0, LOOP_DIAGONAL_SUM); + + __ bind(SKIP_DIAGONAL_SUM); + + // Shift back up and set low bit + // Shifts 1 bit left up to len positions. Assumes no leading zeros + // begin + __ cmpwi (CCR0, out_len, 0); + __ ble (CCR0, SKIP_LSHIFT); + __ li (i, 0); + __ lwz (c, 0, out); + __ subi (b, out_len, 1); + __ mtctr (b); + + __ bind(LOOP_LSHIFT); + __ mr (b, c); + __ addi (cs, i, 4); + __ lwzx (c, out, cs); + + __ sldi (b, b, 1); + __ srwi (cs, c, 31); + __ orr (b, b, cs); + __ stwx (b, i, out); + + __ addi (i, i, 4); + __ bdnz (LOOP_LSHIFT); + + __ sldi (c, out_len, 2); + __ subi (c, c, 4); + __ lwzx (b, out, c); + __ sldi (b, b, 1); + __ stwx (b, out, c); + + __ bind(SKIP_LSHIFT); + // end + + // Set low bit + __ sldi (i, in_len, 2); + __ subi (i, i, 4); + __ lwzx (i, in, i); + __ sldi (c, out_len, 2); + __ subi (c, c, 4); + __ lwzx (b, out, c); + + __ andi (i, i, 1); + __ orr (i, b, i); + + __ stwx (i, out, c); + + // Restore non-volatile regs. + current_offs = -8; + __ ld(R28, current_offs, R1_SP); current_offs -= 8; + __ ld(R27, current_offs, R1_SP); current_offs -= 8; + __ ld(R26, current_offs, R1_SP); current_offs -= 8; + __ ld(R25, current_offs, R1_SP); current_offs -= 8; + __ ld(R24, current_offs, R1_SP); current_offs -= 8; + __ ld(R23, current_offs, R1_SP); current_offs -= 8; + __ ld(R22, current_offs, R1_SP); current_offs -= 8; + __ ld(R21, current_offs, R1_SP); current_offs -= 8; + __ ld(R20, current_offs, R1_SP); current_offs -= 8; + __ ld(R19, current_offs, R1_SP); current_offs -= 8; + __ ld(R18, current_offs, R1_SP); current_offs -= 8; + __ ld(R17, current_offs, R1_SP); current_offs -= 8; + __ ld(R16, current_offs, R1_SP); current_offs -= 8; + __ ld(R15, current_offs, R1_SP); current_offs -= 8; + __ ld(R14, current_offs, R1_SP); + + __ mr(ret, out); + __ blr(); + + return start; + } /** * Arguments: @@ -3500,6 +3794,12 @@ class StubGenerator: public StubCodeGenerator { } #endif + if (UseSquareToLenIntrinsic) { + StubRoutines::_squareToLen = generate_squareToLen(); + } + if (UseMulAddIntrinsic) { + StubRoutines::_mulAdd = generate_mulAdd(); + } if (UseMontgomeryMultiplyIntrinsic) { StubRoutines::_montgomeryMultiply = CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_multiply); @@ -3514,6 +3814,14 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); } + if (UseSHA256Intrinsics) { + StubRoutines::_sha256_implCompress = generate_sha256_implCompress(false, "sha256_implCompress"); + StubRoutines::_sha256_implCompressMB = generate_sha256_implCompress(true, "sha256_implCompressMB"); + } + if (UseSHA512Intrinsics) { + StubRoutines::_sha512_implCompress = generate_sha512_implCompress(false, "sha512_implCompress"); + StubRoutines::_sha512_implCompressMB = generate_sha512_implCompress(true, "sha512_implCompressMB"); + } } public: diff --git a/src/hotspot/cpu/ppc/stubRoutines_ppc.hpp b/src/hotspot/cpu/ppc/stubRoutines_ppc.hpp index dcda6be8a76..da480d73aee 100644 --- a/src/hotspot/cpu/ppc/stubRoutines_ppc.hpp +++ b/src/hotspot/cpu/ppc/stubRoutines_ppc.hpp @@ -34,7 +34,7 @@ static bool returns_to_call_stub(address return_pc) { return return_pc == _call_ enum platform_dependent_constants { code_size1 = 20000, // simply increase if too small (assembler will crash if too small) - code_size2 = 20000 // simply increase if too small (assembler will crash if too small) + code_size2 = 24000 // simply increase if too small (assembler will crash if too small) }; // CRC32 Intrinsics. diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index 32e25e9038c..2216890dd6b 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -1470,10 +1470,6 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // TODO PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size"); __ stw(R0, thread_(thread_state)); - if (UseMembar) { - __ fence(); - } - //============================================================================= // Call the native method. Argument registers must not have been // overwritten since "__ call_stub(signature_handler);" (except for @@ -1594,9 +1590,6 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ li(R0/*thread_state*/, _thread_in_Java); __ release(); __ stw(R0/*thread_state*/, thread_(thread_state)); - if (UseMembar) { - __ fence(); - } if (CheckJNICalls) { // clear_pending_jni_exception_check diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp index 43f6ad1c591..282ffeb218b 100644 --- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp @@ -2224,6 +2224,7 @@ void TemplateTable::load_field_cp_cache_entry(Register Robj, if (is_static) { __ ld(Robj, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::f1_offset()), Rcache); __ ld(Robj, in_bytes(Klass::java_mirror_offset()), Robj); + __ resolve_oop_handle(Robj); // Acquire not needed here. Following access has an address dependency on this value. } } diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp index 4db0a9c20cb..a145a52c48a 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp @@ -107,13 +107,23 @@ void VM_Version::initialize() { // TODO: PPC port PdScheduling::power6SectorSize = 0x20; } - MaxVectorSize = 8; + if (PowerArchitecturePPC64 >= 8) { + if (FLAG_IS_DEFAULT(SuperwordUseVSX)) { + FLAG_SET_ERGO(bool, SuperwordUseVSX, true); + } + } else { + if (SuperwordUseVSX) { + warning("SuperwordUseVSX specified, but needs at least Power8."); + FLAG_SET_DEFAULT(SuperwordUseVSX, false); + } + } + MaxVectorSize = SuperwordUseVSX ? 16 : 8; #endif // Create and print feature-string. char buf[(num_features+1) * 16]; // Max 16 chars per feature. jio_snprintf(buf, sizeof(buf), - "ppc64%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + "ppc64%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", (has_fsqrt() ? " fsqrt" : ""), (has_isel() ? " isel" : ""), (has_lxarxeh() ? " lxarxeh" : ""), @@ -130,7 +140,8 @@ void VM_Version::initialize() { (has_mfdscr() ? " mfdscr" : ""), (has_vsx() ? " vsx" : ""), (has_ldbrx() ? " ldbrx" : ""), - (has_stdbrx() ? " stdbrx" : "") + (has_stdbrx() ? " stdbrx" : ""), + (has_vshasig() ? " sha" : "") // Make sure number of %s matches num_features! ); _features_string = os::strdup(buf); @@ -138,8 +149,7 @@ void VM_Version::initialize() { print_features(); } - // PPC64 supports 8-byte compare-exchange operations (see - // Atomic::cmpxchg and StubGenerator::generate_atomic_cmpxchg_ptr) + // PPC64 supports 8-byte compare-exchange operations (see Atomic::cmpxchg) // and 'atomic long memory ops' (see Unsafe_GetLongVolatile). _supports_cx8 = true; @@ -200,7 +210,6 @@ void VM_Version::initialize() { } // The AES intrinsic stubs require AES instruction support. -#if defined(VM_LITTLE_ENDIAN) if (has_vcipher()) { if (FLAG_IS_DEFAULT(UseAES)) { UseAES = true; @@ -221,18 +230,6 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseAESIntrinsics, false); } -#else - if (UseAES) { - warning("AES instructions are not available on this CPU"); - FLAG_SET_DEFAULT(UseAES, false); - } - if (UseAESIntrinsics) { - if (!FLAG_IS_DEFAULT(UseAESIntrinsics)) - warning("AES intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseAESIntrinsics, false); - } -#endif - if (UseAESCTRIntrinsics) { warning("AES/CTR intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); @@ -247,17 +244,49 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseFMA, true); } - if (UseSHA) { - warning("SHA instructions are not available on this CPU"); + if (has_vshasig()) { + if (FLAG_IS_DEFAULT(UseSHA)) { + UseSHA = true; + } + } else if (UseSHA) { + if (!FLAG_IS_DEFAULT(UseSHA)) + warning("SHA instructions are not available on this CPU"); FLAG_SET_DEFAULT(UseSHA, false); } - if (UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics) { - warning("SHA intrinsics are not available on this CPU"); + + if (UseSHA1Intrinsics) { + warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UseSHA1Intrinsics, false); + } + + if (UseSHA && has_vshasig()) { + if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) { + FLAG_SET_DEFAULT(UseSHA256Intrinsics, true); + } + } else if (UseSHA256Intrinsics) { + warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); + } + + if (UseSHA && has_vshasig()) { + if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) { + FLAG_SET_DEFAULT(UseSHA512Intrinsics, true); + } + } else if (UseSHA512Intrinsics) { + warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); } + if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) { + FLAG_SET_DEFAULT(UseSHA, false); + } + + if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) { + UseSquareToLenIntrinsic = true; + } + if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) { + UseMulAddIntrinsic = true; + } if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { UseMultiplyToLenIntrinsic = true; } @@ -657,6 +686,7 @@ void VM_Version::determine_features() { a->lxvd2x(VSR0, R3_ARG1); // code[14] -> vsx a->ldbrx(R7, R3_ARG1, R4_ARG2); // code[15] -> ldbrx a->stdbrx(R7, R3_ARG1, R4_ARG2); // code[16] -> stdbrx + a->vshasigmaw(VR0, VR1, 1, 0xF); // code[17] -> vshasig a->blr(); // Emit function to set one cache line to zero. Emit function descriptor and get pointer to it. @@ -708,6 +738,7 @@ void VM_Version::determine_features() { if (code[feature_cntr++]) features |= vsx_m; if (code[feature_cntr++]) features |= ldbrx_m; if (code[feature_cntr++]) features |= stdbrx_m; + if (code[feature_cntr++]) features |= vshasig_m; // Print the detection code. if (PrintAssembly) { diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.hpp b/src/hotspot/cpu/ppc/vm_version_ppc.hpp index f7d5ea73aca..eec629f1d3e 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.hpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.hpp @@ -49,6 +49,7 @@ protected: vsx, ldbrx, stdbrx, + vshasig, num_features // last entry to count features }; enum Feature_Flag_Set { @@ -64,6 +65,7 @@ protected: vand_m = (1 << vand ), lqarx_m = (1 << lqarx ), vcipher_m = (1 << vcipher), + vshasig_m = (1 << vshasig), vpmsumb_m = (1 << vpmsumb), tcheck_m = (1 << tcheck ), mfdscr_m = (1 << mfdscr ), @@ -106,6 +108,7 @@ public: static bool has_vsx() { return (_features & vsx_m) != 0; } static bool has_ldbrx() { return (_features & ldbrx_m) != 0; } static bool has_stdbrx() { return (_features & stdbrx_m) != 0; } + static bool has_vshasig() { return (_features & vshasig_m) != 0; } static bool has_mtfprd() { return has_vpmsumb(); } // alias for P8 // Assembler testing diff --git a/src/hotspot/cpu/s390/assembler_s390.hpp b/src/hotspot/cpu/s390/assembler_s390.hpp index 8a7ae9d0756..a839700259c 100644 --- a/src/hotspot/cpu/s390/assembler_s390.hpp +++ b/src/hotspot/cpu/s390/assembler_s390.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 SAP SE. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017 SAP SE. 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 @@ -250,7 +250,6 @@ class Address VALUE_OBJ_CLASS_SPEC { bool is_RSform() { return has_base() && !has_index() && is_disp12(); } bool is_RSYform() { return has_base() && !has_index() && is_disp20(); } bool is_RXform() { return has_base() && has_index() && is_disp12(); } - bool is_RXEform() { return has_base() && has_index() && is_disp12(); } bool is_RXYform() { return has_base() && has_index() && is_disp20(); } bool uses(Register r) { return _base == r || _index == r; }; @@ -1093,7 +1092,201 @@ class Assembler : public AbstractAssembler { #define TRTT_ZOPC (unsigned int)(0xb9 << 24 | 0x90 << 16) -// Miscellaneous Operations +//--------------------------- +//-- Vector Instructions -- +//--------------------------- + +//---< Vector Support Instructions >--- + +//--- Load (memory) --- + +#define VLM_ZOPC (unsigned long)(0xe7L << 40 | 0x36L << 0) // load full vreg range (n * 128 bit) +#define VL_ZOPC (unsigned long)(0xe7L << 40 | 0x06L << 0) // load full vreg (128 bit) +#define VLEB_ZOPC (unsigned long)(0xe7L << 40 | 0x00L << 0) // load vreg element (8 bit) +#define VLEH_ZOPC (unsigned long)(0xe7L << 40 | 0x01L << 0) // load vreg element (16 bit) +#define VLEF_ZOPC (unsigned long)(0xe7L << 40 | 0x03L << 0) // load vreg element (32 bit) +#define VLEG_ZOPC (unsigned long)(0xe7L << 40 | 0x02L << 0) // load vreg element (64 bit) + +#define VLREP_ZOPC (unsigned long)(0xe7L << 40 | 0x05L << 0) // load and replicate into all vector elements +#define VLLEZ_ZOPC (unsigned long)(0xe7L << 40 | 0x04L << 0) // load logical element and zero. + +// vector register gather +#define VGEF_ZOPC (unsigned long)(0xe7L << 40 | 0x13L << 0) // gather element (32 bit), V1(M3) = [D2(V2(M3),B2)] +#define VGEG_ZOPC (unsigned long)(0xe7L << 40 | 0x12L << 0) // gather element (64 bit), V1(M3) = [D2(V2(M3),B2)] +// vector register scatter +#define VSCEF_ZOPC (unsigned long)(0xe7L << 40 | 0x1bL << 0) // vector scatter element FW +#define VSCEG_ZOPC (unsigned long)(0xe7L << 40 | 0x1aL << 0) // vector scatter element DW + +#define VLBB_ZOPC (unsigned long)(0xe7L << 40 | 0x07L << 0) // load vreg to block boundary (load to alignment). +#define VLL_ZOPC (unsigned long)(0xe7L << 40 | 0x37L << 0) // load vreg with length. + +//--- Load (register) --- + +#define VLR_ZOPC (unsigned long)(0xe7L << 40 | 0x56L << 0) // copy full vreg (128 bit) +#define VLGV_ZOPC (unsigned long)(0xe7L << 40 | 0x21L << 0) // copy vreg element -> GR +#define VLVG_ZOPC (unsigned long)(0xe7L << 40 | 0x22L << 0) // copy GR -> vreg element +#define VLVGP_ZOPC (unsigned long)(0xe7L << 40 | 0x62L << 0) // copy GR2, GR3 (disjoint pair) -> vreg + +// vector register pack: cut in half the size the source vector elements +#define VPK_ZOPC (unsigned long)(0xe7L << 40 | 0x94L << 0) // just cut +#define VPKS_ZOPC (unsigned long)(0xe7L << 40 | 0x97L << 0) // saturate as signed values +#define VPKLS_ZOPC (unsigned long)(0xe7L << 40 | 0x95L << 0) // saturate as unsigned values + +// vector register unpack: double in size the source vector elements +#define VUPH_ZOPC (unsigned long)(0xe7L << 40 | 0xd7L << 0) // signed, left half of the source vector elements +#define VUPLH_ZOPC (unsigned long)(0xe7L << 40 | 0xd5L << 0) // unsigned, left half of the source vector elements +#define VUPL_ZOPC (unsigned long)(0xe7L << 40 | 0xd6L << 0) // signed, right half of the source vector elements +#define VUPLL_ZOPC (unsigned long)(0xe7L << 40 | 0xd4L << 0) // unsigned, right half of the source vector element + +// vector register merge +#define VMRH_ZOPC (unsigned long)(0xe7L << 40 | 0x61L << 0) // register merge high (left half of source registers) +#define VMRL_ZOPC (unsigned long)(0xe7L << 40 | 0x60L << 0) // register merge low (right half of source registers) + +// vector register permute +#define VPERM_ZOPC (unsigned long)(0xe7L << 40 | 0x8cL << 0) // vector permute +#define VPDI_ZOPC (unsigned long)(0xe7L << 40 | 0x84L << 0) // vector permute DW immediate + +// vector register replicate +#define VREP_ZOPC (unsigned long)(0xe7L << 40 | 0x4dL << 0) // vector replicate +#define VREPI_ZOPC (unsigned long)(0xe7L << 40 | 0x45L << 0) // vector replicate immediate +#define VSEL_ZOPC (unsigned long)(0xe7L << 40 | 0x8dL << 0) // vector select + +#define VSEG_ZOPC (unsigned long)(0xe7L << 40 | 0x5fL << 0) // vector sign-extend to DW (rightmost element in each DW). + +//--- Load (immediate) --- + +#define VLEIB_ZOPC (unsigned long)(0xe7L << 40 | 0x40L << 0) // load vreg element (16 bit imm to 8 bit) +#define VLEIH_ZOPC (unsigned long)(0xe7L << 40 | 0x41L << 0) // load vreg element (16 bit imm to 16 bit) +#define VLEIF_ZOPC (unsigned long)(0xe7L << 40 | 0x43L << 0) // load vreg element (16 bit imm to 32 bit) +#define VLEIG_ZOPC (unsigned long)(0xe7L << 40 | 0x42L << 0) // load vreg element (16 bit imm to 64 bit) + +//--- Store --- + +#define VSTM_ZOPC (unsigned long)(0xe7L << 40 | 0x3eL << 0) // store full vreg range (n * 128 bit) +#define VST_ZOPC (unsigned long)(0xe7L << 40 | 0x0eL << 0) // store full vreg (128 bit) +#define VSTEB_ZOPC (unsigned long)(0xe7L << 40 | 0x08L << 0) // store vreg element (8 bit) +#define VSTEH_ZOPC (unsigned long)(0xe7L << 40 | 0x09L << 0) // store vreg element (16 bit) +#define VSTEF_ZOPC (unsigned long)(0xe7L << 40 | 0x0bL << 0) // store vreg element (32 bit) +#define VSTEG_ZOPC (unsigned long)(0xe7L << 40 | 0x0aL << 0) // store vreg element (64 bit) +#define VSTL_ZOPC (unsigned long)(0xe7L << 40 | 0x3fL << 0) // store vreg with length. + +//--- Misc --- + +#define VGM_ZOPC (unsigned long)(0xe7L << 40 | 0x46L << 0) // generate bit mask, [start..end] = '1', else '0' +#define VGBM_ZOPC (unsigned long)(0xe7L << 40 | 0x44L << 0) // generate byte mask, bits(imm16) -> bytes + +//---< Vector Arithmetic Instructions >--- + +// Load +#define VLC_ZOPC (unsigned long)(0xe7L << 40 | 0xdeL << 0) // V1 := -V2, element size = 2**m +#define VLP_ZOPC (unsigned long)(0xe7L << 40 | 0xdfL << 0) // V1 := |V2|, element size = 2**m + +// ADD +#define VA_ZOPC (unsigned long)(0xe7L << 40 | 0xf3L << 0) // V1 := V2 + V3, element size = 2**m +#define VACC_ZOPC (unsigned long)(0xe7L << 40 | 0xf1L << 0) // V1 := carry(V2 + V3), element size = 2**m + +// SUB +#define VS_ZOPC (unsigned long)(0xe7L << 40 | 0xf7L << 0) // V1 := V2 - V3, element size = 2**m +#define VSCBI_ZOPC (unsigned long)(0xe7L << 40 | 0xf5L << 0) // V1 := borrow(V2 - V3), element size = 2**m + +// MUL +#define VML_ZOPC (unsigned long)(0xe7L << 40 | 0xa2L << 0) // V1 := V2 * V3, element size = 2**m +#define VMH_ZOPC (unsigned long)(0xe7L << 40 | 0xa3L << 0) // V1 := V2 * V3, element size = 2**m +#define VMLH_ZOPC (unsigned long)(0xe7L << 40 | 0xa1L << 0) // V1 := V2 * V3, element size = 2**m, unsigned +#define VME_ZOPC (unsigned long)(0xe7L << 40 | 0xa6L << 0) // V1 := V2 * V3, element size = 2**m +#define VMLE_ZOPC (unsigned long)(0xe7L << 40 | 0xa4L << 0) // V1 := V2 * V3, element size = 2**m, unsigned +#define VMO_ZOPC (unsigned long)(0xe7L << 40 | 0xa7L << 0) // V1 := V2 * V3, element size = 2**m +#define VMLO_ZOPC (unsigned long)(0xe7L << 40 | 0xa5L << 0) // V1 := V2 * V3, element size = 2**m, unsigned + +// MUL & ADD +#define VMAL_ZOPC (unsigned long)(0xe7L << 40 | 0xaaL << 0) // V1 := V2 * V3 + V4, element size = 2**m +#define VMAH_ZOPC (unsigned long)(0xe7L << 40 | 0xabL << 0) // V1 := V2 * V3 + V4, element size = 2**m +#define VMALH_ZOPC (unsigned long)(0xe7L << 40 | 0xa9L << 0) // V1 := V2 * V3 + V4, element size = 2**m, unsigned +#define VMAE_ZOPC (unsigned long)(0xe7L << 40 | 0xaeL << 0) // V1 := V2 * V3 + V4, element size = 2**m +#define VMALE_ZOPC (unsigned long)(0xe7L << 40 | 0xacL << 0) // V1 := V2 * V3 + V4, element size = 2**m, unsigned +#define VMAO_ZOPC (unsigned long)(0xe7L << 40 | 0xafL << 0) // V1 := V2 * V3 + V4, element size = 2**m +#define VMALO_ZOPC (unsigned long)(0xe7L << 40 | 0xadL << 0) // V1 := V2 * V3 + V4, element size = 2**m, unsigned + +// Vector SUM +#define VSUM_ZOPC (unsigned long)(0xe7L << 40 | 0x64L << 0) // V1[j] := toFW(sum(V2[i]) + V3[j]), subelements: byte or HW +#define VSUMG_ZOPC (unsigned long)(0xe7L << 40 | 0x65L << 0) // V1[j] := toDW(sum(V2[i]) + V3[j]), subelements: HW or FW +#define VSUMQ_ZOPC (unsigned long)(0xe7L << 40 | 0x67L << 0) // V1[j] := toQW(sum(V2[i]) + V3[j]), subelements: FW or DW + +// Average +#define VAVG_ZOPC (unsigned long)(0xe7L << 40 | 0xf2L << 0) // V1 := (V2+V3+1)/2, signed, element size = 2**m +#define VAVGL_ZOPC (unsigned long)(0xe7L << 40 | 0xf0L << 0) // V1 := (V2+V3+1)/2, unsigned, element size = 2**m + +// VECTOR Galois Field Multiply Sum +#define VGFM_ZOPC (unsigned long)(0xe7L << 40 | 0xb4L << 0) +#define VGFMA_ZOPC (unsigned long)(0xe7L << 40 | 0xbcL << 0) + +//---< Vector Logical Instructions >--- + +// AND +#define VN_ZOPC (unsigned long)(0xe7L << 40 | 0x68L << 0) // V1 := V2 & V3, element size = 2**m +#define VNC_ZOPC (unsigned long)(0xe7L << 40 | 0x69L << 0) // V1 := V2 & ~V3, element size = 2**m + +// XOR +#define VX_ZOPC (unsigned long)(0xe7L << 40 | 0x6dL << 0) // V1 := V2 ^ V3, element size = 2**m + +// NOR +#define VNO_ZOPC (unsigned long)(0xe7L << 40 | 0x6bL << 0) // V1 := !(V2 | V3), element size = 2**m + +// OR +#define VO_ZOPC (unsigned long)(0xe7L << 40 | 0x6aL << 0) // V1 := V2 | V3, element size = 2**m + +// Comparison (element-wise) +#define VCEQ_ZOPC (unsigned long)(0xe7L << 40 | 0xf8L << 0) // V1 := (V2 == V3) ? 0xffff : 0x0000, element size = 2**m +#define VCH_ZOPC (unsigned long)(0xe7L << 40 | 0xfbL << 0) // V1 := (V2 > V3) ? 0xffff : 0x0000, element size = 2**m, signed +#define VCHL_ZOPC (unsigned long)(0xe7L << 40 | 0xf9L << 0) // V1 := (V2 > V3) ? 0xffff : 0x0000, element size = 2**m, unsigned + +// Max/Min (element-wise) +#define VMX_ZOPC (unsigned long)(0xe7L << 40 | 0xffL << 0) // V1 := (V2 > V3) ? V2 : V3, element size = 2**m, signed +#define VMXL_ZOPC (unsigned long)(0xe7L << 40 | 0xfdL << 0) // V1 := (V2 > V3) ? V2 : V3, element size = 2**m, unsigned +#define VMN_ZOPC (unsigned long)(0xe7L << 40 | 0xfeL << 0) // V1 := (V2 < V3) ? V2 : V3, element size = 2**m, signed +#define VMNL_ZOPC (unsigned long)(0xe7L << 40 | 0xfcL << 0) // V1 := (V2 < V3) ? V2 : V3, element size = 2**m, unsigned + +// Leading/Trailing Zeros, population count +#define VCLZ_ZOPC (unsigned long)(0xe7L << 40 | 0x53L << 0) // V1 := leadingzeros(V2), element size = 2**m +#define VCTZ_ZOPC (unsigned long)(0xe7L << 40 | 0x52L << 0) // V1 := trailingzeros(V2), element size = 2**m +#define VPOPCT_ZOPC (unsigned long)(0xe7L << 40 | 0x50L << 0) // V1 := popcount(V2), bytewise!! + +// Rotate/Shift +#define VERLLV_ZOPC (unsigned long)(0xe7L << 40 | 0x73L << 0) // V1 := rotateleft(V2), rotate count in V3 element +#define VERLL_ZOPC (unsigned long)(0xe7L << 40 | 0x33L << 0) // V1 := rotateleft(V3), rotate count from d2(b2). +#define VERIM_ZOPC (unsigned long)(0xe7L << 40 | 0x72L << 0) // Rotate then insert under mask. Read Principles of Operation!! + +#define VESLV_ZOPC (unsigned long)(0xe7L << 40 | 0x70L << 0) // V1 := SLL(V2, V3), unsigned, element-wise +#define VESL_ZOPC (unsigned long)(0xe7L << 40 | 0x30L << 0) // V1 := SLL(V3), unsigned, shift count from d2(b2). + +#define VESRAV_ZOPC (unsigned long)(0xe7L << 40 | 0x7AL << 0) // V1 := SRA(V2, V3), signed, element-wise +#define VESRA_ZOPC (unsigned long)(0xe7L << 40 | 0x3AL << 0) // V1 := SRA(V3), signed, shift count from d2(b2). +#define VESRLV_ZOPC (unsigned long)(0xe7L << 40 | 0x78L << 0) // V1 := SRL(V2, V3), unsigned, element-wise +#define VESRL_ZOPC (unsigned long)(0xe7L << 40 | 0x38L << 0) // V1 := SRL(V3), unsigned, shift count from d2(b2). + +#define VSL_ZOPC (unsigned long)(0xe7L << 40 | 0x74L << 0) // V1 := SLL(V2), unsigned, bit-count +#define VSLB_ZOPC (unsigned long)(0xe7L << 40 | 0x75L << 0) // V1 := SLL(V2), unsigned, byte-count +#define VSLDB_ZOPC (unsigned long)(0xe7L << 40 | 0x77L << 0) // V1 := SLL((V2,V3)), unsigned, byte-count + +#define VSRA_ZOPC (unsigned long)(0xe7L << 40 | 0x7eL << 0) // V1 := SRA(V2), signed, bit-count +#define VSRAB_ZOPC (unsigned long)(0xe7L << 40 | 0x7fL << 0) // V1 := SRA(V2), signed, byte-count +#define VSRL_ZOPC (unsigned long)(0xe7L << 40 | 0x7cL << 0) // V1 := SRL(V2), unsigned, bit-count +#define VSRLB_ZOPC (unsigned long)(0xe7L << 40 | 0x7dL << 0) // V1 := SRL(V2), unsigned, byte-count + +// Test under Mask +#define VTM_ZOPC (unsigned long)(0xe7L << 40 | 0xd8L << 0) // Like TM, set CC according to state of selected bits. + +//---< Vector String Instructions >--- +#define VFAE_ZOPC (unsigned long)(0xe7L << 40 | 0x82L << 0) // Find any element +#define VFEE_ZOPC (unsigned long)(0xe7L << 40 | 0x80L << 0) // Find element equal +#define VFENE_ZOPC (unsigned long)(0xe7L << 40 | 0x81L << 0) // Find element not equal +#define VSTRC_ZOPC (unsigned long)(0xe7L << 40 | 0x8aL << 0) // String range compare +#define VISTR_ZOPC (unsigned long)(0xe7L << 40 | 0x5cL << 0) // Isolate String + + +//-------------------------------- +//-- Miscellaneous Operations -- +//-------------------------------- // Execute #define EX_ZOPC (unsigned int)(68L << 24) @@ -1117,7 +1310,6 @@ class Assembler : public AbstractAssembler { #define LAOG_ZOPC (unsigned long)(0xebL << 40 | 0xe6L) // z196 // System Functions -#define STCK_ZOPC (unsigned int)(0xb2 << 24 | 0x05 << 16) #define STCKF_ZOPC (unsigned int)(0xb2 << 24 | 0x7c << 16) #define STFLE_ZOPC (unsigned int)(0xb2 << 24 | 0xb0 << 16) #define ECTG_ZOPC (unsigned long)(0xc8L <<40 | 0x01L << 32) // z10 @@ -1244,10 +1436,18 @@ class Assembler : public AbstractAssembler { // unsigned arithmetic calculation instructions // Mask bit#0 is not used by these instructions. // There is no indication of overflow for these instr. - bcondLogZero = 2, - bcondLogNotZero = 5, + bcondLogZero_NoCarry = 8, + bcondLogZero_Carry = 2, + // bcondLogZero_Borrow = 8, // This CC is never generated. + bcondLogZero_NoBorrow = 2, + bcondLogZero = bcondLogZero_Carry | bcondLogZero_NoCarry, + bcondLogNotZero_NoCarry = 4, + bcondLogNotZero_Carry = 1, bcondLogNotZero_Borrow = 4, bcondLogNotZero_NoBorrow = 1, + bcondLogNotZero = bcondLogNotZero_Carry | bcondLogNotZero_NoCarry, + bcondLogCarry = bcondLogZero_Carry | bcondLogNotZero_Carry, + bcondLogBorrow = /* bcondLogZero_Borrow | */ bcondLogNotZero_Borrow, // string search instructions bcondFound = 4, bcondNotFound = 2, @@ -1280,6 +1480,29 @@ class Assembler : public AbstractAssembler { to_minus_infinity = 7 }; + // Vector Register Element Type. + enum VRegElemType { + VRET_BYTE = 0, + VRET_HW = 1, + VRET_FW = 2, + VRET_DW = 3, + VRET_QW = 4 + }; + + // Vector Operation Result Control. + // This is a set of flags used in some vector instructions to control + // the result (side) effects of instruction execution. + enum VOpRC { + VOPRC_CCSET = 0b0001, // set the CC. + VOPRC_CCIGN = 0b0000, // ignore, don't set CC. + VOPRC_ZS = 0b0010, // Zero Search. Additional, elementwise, comparison against zero. + VOPRC_NOZS = 0b0000, // No Zero Search. + VOPRC_RTBYTEIX = 0b0100, // generate byte index to lowest element with true comparison. + VOPRC_RTBITVEC = 0b0000, // generate bit vector, all 1s for true, all 0s for false element comparisons. + VOPRC_INVERT = 0b1000, // invert comparison results. + VOPRC_NOINVERT = 0b0000 // use comparison results as is, do not invert. + }; + // Inverse condition code, i.e. determine "15 - cc" for a given condition code cc. static branch_condition inverse_condition(branch_condition cc); static branch_condition inverse_float_condition(branch_condition cc); @@ -1376,6 +1599,65 @@ class Assembler : public AbstractAssembler { return r; } + static int64_t rsmask_48( Address a) { assert(a.is_RSform(), "bad address format"); return rsmask_48( a.disp12(), a.base()); } + static int64_t rxmask_48( Address a) { if (a.is_RXform()) { return rxmask_48( a.disp12(), a.index(), a.base()); } + else if (a.is_RSform()) { return rsmask_48( a.disp12(), a.base()); } + else { guarantee(false, "bad address format"); return 0; } + } + static int64_t rsymask_48(Address a) { assert(a.is_RSYform(), "bad address format"); return rsymask_48(a.disp20(), a.base()); } + static int64_t rxymask_48(Address a) { if (a.is_RXYform()) { return rxymask_48( a.disp20(), a.index(), a.base()); } + else if (a.is_RSYform()) { return rsymask_48( a.disp20(), a.base()); } + else { guarantee(false, "bad address format"); return 0; } + } + + static int64_t rsmask_48( int64_t d2, Register b2) { return uimm12(d2, 20, 48) | regz(b2, 16, 48); } + static int64_t rxmask_48( int64_t d2, Register x2, Register b2) { return uimm12(d2, 20, 48) | reg(x2, 12, 48) | regz(b2, 16, 48); } + static int64_t rsymask_48(int64_t d2, Register b2) { return simm20(d2) | regz(b2, 16, 48); } + static int64_t rxymask_48(int64_t d2, Register x2, Register b2) { return simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48); } + + // Address calculated from d12(vx,b) - vx is vector index register. + static int64_t rvmask_48( int64_t d2, VectorRegister x2, Register b2) { return uimm12(d2, 20, 48) | vreg(x2, 12) | regz(b2, 16, 48); } + + static int64_t vreg_mask(VectorRegister v, int pos) { + return vreg(v, pos) | v->RXB_mask(pos); + } + + // Vector Element Size Control. 4-bit field which indicates the size of the vector elements. + static int64_t vesc_mask(int64_t size, int min_size, int max_size, int pos) { + // min_size - minimum element size. Not all instructions support element sizes beginning with "byte". + // max_size - maximum element size. Not all instructions support element sizes up to "QW". + assert((min_size <= size) && (size <= max_size), "element size control out of range"); + return uimm4(size, pos, 48); + } + + // Vector Element IndeX. 4-bit field which indexes the target vector element. + static int64_t veix_mask(int64_t ix, int el_size, int pos) { + // el_size - size of the vector element. This is a VRegElemType enum value. + // ix - vector element index. + int max_ix = -1; + switch (el_size) { + case VRET_BYTE: max_ix = 15; break; + case VRET_HW: max_ix = 7; break; + case VRET_FW: max_ix = 3; break; + case VRET_DW: max_ix = 1; break; + case VRET_QW: max_ix = 0; break; + default: guarantee(false, "bad vector element size %d", el_size); break; + } + assert((0 <= ix) && (ix <= max_ix), "element size out of range (0 <= %ld <= %d)", ix, max_ix); + return uimm4(ix, pos, 48); + } + + // Vector Operation Result Control. 4-bit field. + static int64_t voprc_any(int64_t flags, int pos, int64_t allowed_flags = 0b1111) { + assert((flags & allowed_flags) == flags, "Invalid VOPRC_* flag combination: %d", (int)flags); + return uimm4(flags, pos, 48); + } + + // Vector Operation Result Control. Condition code setting. + static int64_t voprc_ccmask(int64_t flags, int pos) { + return voprc_any(flags, pos, VOPRC_CCIGN | VOPRC_CCSET); + } + public: //-------------------------------------------------- @@ -1453,6 +1735,8 @@ class Assembler : public AbstractAssembler { static long imm24(int64_t i24, int s, int len) { return imm(i24, 24) << (len-s-24); } static long imm32(int64_t i32, int s, int len) { return imm(i32, 32) << (len-s-32); } + static long vreg(VectorRegister v, int pos) { const int len = 48; return u_field(v->encoding()&0x0f, (len-pos)-1, (len-pos)-4) | v->RXB_mask(pos); } + static long fregt(FloatRegister r, int s, int len) { return freg(r,s,len); } static long freg( FloatRegister r, int s, int len) { return u_field(r->encoding(), (len-s)-1, (len-s)-4); } @@ -1840,13 +2124,16 @@ class Assembler : public AbstractAssembler { inline void z_alsi( const Address& d, int64_t i2); // add logical *(d) += i2_imm8 ; uint32 -- z10 inline void z_algsi(const Address& d, int64_t i2); // add logical *(d) += i2_imm8 ; uint64 -- z10 - // negate + // sign adjustment inline void z_lcr( Register r1, Register r2 = noreg); // neg r1 = -r2 ; int32 inline void z_lcgr( Register r1, Register r2 = noreg); // neg r1 = -r2 ; int64 inline void z_lcgfr(Register r1, Register r2); // neg r1 = -r2 ; int64 <- int32 inline void z_lnr( Register r1, Register r2 = noreg); // neg r1 = -|r2| ; int32 inline void z_lngr( Register r1, Register r2 = noreg); // neg r1 = -|r2| ; int64 inline void z_lngfr(Register r1, Register r2); // neg r1 = -|r2| ; int64 <- int32 + inline void z_lpr( Register r1, Register r2 = noreg); // r1 = |r2| ; int32 + inline void z_lpgr( Register r1, Register r2 = noreg); // r1 = |r2| ; int64 + inline void z_lpgfr(Register r1, Register r2); // r1 = |r2| ; int64 <- int32 // subtract intstructions // sub registers @@ -2125,6 +2412,422 @@ class Assembler : public AbstractAssembler { inline void z_trtt(Register r1, Register r2, int64_t m3); + //--------------------------- + //-- Vector Instructions -- + //--------------------------- + + //---< Vector Support Instructions >--- + + // Load (transfer from memory) + inline void z_vlm( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_vl( VectorRegister v1, int64_t d2, Register x2, Register b2); + inline void z_vleb( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); + inline void z_vleh( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); + inline void z_vlef( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); + inline void z_vleg( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); + + // Gather/Scatter + inline void z_vgef( VectorRegister v1, int64_t d2, VectorRegister vx2, Register b2, int64_t m3); + inline void z_vgeg( VectorRegister v1, int64_t d2, VectorRegister vx2, Register b2, int64_t m3); + + inline void z_vscef( VectorRegister v1, int64_t d2, VectorRegister vx2, Register b2, int64_t m3); + inline void z_vsceg( VectorRegister v1, int64_t d2, VectorRegister vx2, Register b2, int64_t m3); + + // load and replicate + inline void z_vlrep( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); + inline void z_vlrepb(VectorRegister v1, int64_t d2, Register x2, Register b2); + inline void z_vlreph(VectorRegister v1, int64_t d2, Register x2, Register b2); + inline void z_vlrepf(VectorRegister v1, int64_t d2, Register x2, Register b2); + inline void z_vlrepg(VectorRegister v1, int64_t d2, Register x2, Register b2); + + inline void z_vllez( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); + inline void z_vllezb(VectorRegister v1, int64_t d2, Register x2, Register b2); + inline void z_vllezh(VectorRegister v1, int64_t d2, Register x2, Register b2); + inline void z_vllezf(VectorRegister v1, int64_t d2, Register x2, Register b2); + inline void z_vllezg(VectorRegister v1, int64_t d2, Register x2, Register b2); + + inline void z_vlbb( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); + inline void z_vll( VectorRegister v1, Register r3, int64_t d2, Register b2); + + // Load (register to register) + inline void z_vlr( VectorRegister v1, VectorRegister v2); + + inline void z_vlgv( Register r1, VectorRegister v3, int64_t d2, Register b2, int64_t m4); + inline void z_vlgvb( Register r1, VectorRegister v3, int64_t d2, Register b2); + inline void z_vlgvh( Register r1, VectorRegister v3, int64_t d2, Register b2); + inline void z_vlgvf( Register r1, VectorRegister v3, int64_t d2, Register b2); + inline void z_vlgvg( Register r1, VectorRegister v3, int64_t d2, Register b2); + + inline void z_vlvg( VectorRegister v1, Register r3, int64_t d2, Register b2, int64_t m4); + inline void z_vlvgb( VectorRegister v1, Register r3, int64_t d2, Register b2); + inline void z_vlvgh( VectorRegister v1, Register r3, int64_t d2, Register b2); + inline void z_vlvgf( VectorRegister v1, Register r3, int64_t d2, Register b2); + inline void z_vlvgg( VectorRegister v1, Register r3, int64_t d2, Register b2); + + inline void z_vlvgp( VectorRegister v1, Register r2, Register r3); + + // vector register pack + inline void z_vpk( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vpkh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vpkf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vpkg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + + inline void z_vpks( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5); + inline void z_vpksh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vpksf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vpksg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vpkshs(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vpksfs(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vpksgs(VectorRegister v1, VectorRegister v2, VectorRegister v3); + + inline void z_vpkls( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5); + inline void z_vpklsh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vpklsf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vpklsg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vpklshs(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vpklsfs(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vpklsgs(VectorRegister v1, VectorRegister v2, VectorRegister v3); + + // vector register unpack (sign-extended) + inline void z_vuph( VectorRegister v1, VectorRegister v2, int64_t m3); + inline void z_vuphb( VectorRegister v1, VectorRegister v2); + inline void z_vuphh( VectorRegister v1, VectorRegister v2); + inline void z_vuphf( VectorRegister v1, VectorRegister v2); + inline void z_vupl( VectorRegister v1, VectorRegister v2, int64_t m3); + inline void z_vuplb( VectorRegister v1, VectorRegister v2); + inline void z_vuplh( VectorRegister v1, VectorRegister v2); + inline void z_vuplf( VectorRegister v1, VectorRegister v2); + + // vector register unpack (zero-extended) + inline void z_vuplh( VectorRegister v1, VectorRegister v2, int64_t m3); + inline void z_vuplhb( VectorRegister v1, VectorRegister v2); + inline void z_vuplhh( VectorRegister v1, VectorRegister v2); + inline void z_vuplhf( VectorRegister v1, VectorRegister v2); + inline void z_vupll( VectorRegister v1, VectorRegister v2, int64_t m3); + inline void z_vupllb( VectorRegister v1, VectorRegister v2); + inline void z_vupllh( VectorRegister v1, VectorRegister v2); + inline void z_vupllf( VectorRegister v1, VectorRegister v2); + + // vector register merge high/low + inline void z_vmrh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmrhb(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmrhh(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmrhf(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmrhg(VectorRegister v1, VectorRegister v2, VectorRegister v3); + + inline void z_vmrl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmrlb(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmrlh(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmrlf(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmrlg(VectorRegister v1, VectorRegister v2, VectorRegister v3); + + // vector register permute + inline void z_vperm( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4); + inline void z_vpdi( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + + // vector register replicate + inline void z_vrep( VectorRegister v1, VectorRegister v3, int64_t imm2, int64_t m4); + inline void z_vrepb( VectorRegister v1, VectorRegister v3, int64_t imm2); + inline void z_vreph( VectorRegister v1, VectorRegister v3, int64_t imm2); + inline void z_vrepf( VectorRegister v1, VectorRegister v3, int64_t imm2); + inline void z_vrepg( VectorRegister v1, VectorRegister v3, int64_t imm2); + inline void z_vrepi( VectorRegister v1, int64_t imm2, int64_t m3); + inline void z_vrepib(VectorRegister v1, int64_t imm2); + inline void z_vrepih(VectorRegister v1, int64_t imm2); + inline void z_vrepif(VectorRegister v1, int64_t imm2); + inline void z_vrepig(VectorRegister v1, int64_t imm2); + + inline void z_vsel( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4); + inline void z_vseg( VectorRegister v1, VectorRegister v2, int64_t imm3); + + // Load (immediate) + inline void z_vleib( VectorRegister v1, int64_t imm2, int64_t m3); + inline void z_vleih( VectorRegister v1, int64_t imm2, int64_t m3); + inline void z_vleif( VectorRegister v1, int64_t imm2, int64_t m3); + inline void z_vleig( VectorRegister v1, int64_t imm2, int64_t m3); + + // Store + inline void z_vstm( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_vst( VectorRegister v1, int64_t d2, Register x2, Register b2); + inline void z_vsteb( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); + inline void z_vsteh( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); + inline void z_vstef( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); + inline void z_vsteg( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); + inline void z_vstl( VectorRegister v1, Register r3, int64_t d2, Register b2); + + // Misc + inline void z_vgm( VectorRegister v1, int64_t imm2, int64_t imm3, int64_t m4); + inline void z_vgmb( VectorRegister v1, int64_t imm2, int64_t imm3); + inline void z_vgmh( VectorRegister v1, int64_t imm2, int64_t imm3); + inline void z_vgmf( VectorRegister v1, int64_t imm2, int64_t imm3); + inline void z_vgmg( VectorRegister v1, int64_t imm2, int64_t imm3); + + inline void z_vgbm( VectorRegister v1, int64_t imm2); + inline void z_vzero( VectorRegister v1); // preferred method to set vreg to all zeroes + inline void z_vone( VectorRegister v1); // preferred method to set vreg to all ones + + //---< Vector Arithmetic Instructions >--- + + // Load + inline void z_vlc( VectorRegister v1, VectorRegister v2, int64_t m3); + inline void z_vlcb( VectorRegister v1, VectorRegister v2); + inline void z_vlch( VectorRegister v1, VectorRegister v2); + inline void z_vlcf( VectorRegister v1, VectorRegister v2); + inline void z_vlcg( VectorRegister v1, VectorRegister v2); + inline void z_vlp( VectorRegister v1, VectorRegister v2, int64_t m3); + inline void z_vlpb( VectorRegister v1, VectorRegister v2); + inline void z_vlph( VectorRegister v1, VectorRegister v2); + inline void z_vlpf( VectorRegister v1, VectorRegister v2); + inline void z_vlpg( VectorRegister v1, VectorRegister v2); + + // ADD + inline void z_va( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vab( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vah( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vaf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vag( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vaq( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vacc( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vaccb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vacch( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vaccf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vaccg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vaccq( VectorRegister v1, VectorRegister v2, VectorRegister v3); + + // SUB + inline void z_vs( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vsb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vsh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vsf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vsg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vsq( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vscbi( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vscbib( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vscbih( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vscbif( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vscbig( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vscbiq( VectorRegister v1, VectorRegister v2, VectorRegister v3); + + // MULTIPLY + inline void z_vml( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmlh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vme( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmle( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmo( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmlo( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + + // MULTIPLY & ADD + inline void z_vmal( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5); + inline void z_vmah( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5); + inline void z_vmalh( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5); + inline void z_vmae( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5); + inline void z_vmale( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5); + inline void z_vmao( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5); + inline void z_vmalo( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5); + + // VECTOR SUM + inline void z_vsum( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vsumb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vsumh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vsumg( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vsumgh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vsumgf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vsumq( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vsumqf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vsumqg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + + // Average + inline void z_vavg( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vavgb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vavgh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vavgf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vavgg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vavgl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vavglb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vavglh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vavglf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vavglg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + + // VECTOR Galois Field Multiply Sum + inline void z_vgfm( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vgfmb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vgfmh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vgfmf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vgfmg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + // VECTOR Galois Field Multiply Sum and Accumulate + inline void z_vgfma( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5); + inline void z_vgfmab( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4); + inline void z_vgfmah( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4); + inline void z_vgfmaf( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4); + inline void z_vgfmag( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4); + + //---< Vector Logical Instructions >--- + + // AND + inline void z_vn( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vnc( VectorRegister v1, VectorRegister v2, VectorRegister v3); + + // XOR + inline void z_vx( VectorRegister v1, VectorRegister v2, VectorRegister v3); + + // NOR + inline void z_vno( VectorRegister v1, VectorRegister v2, VectorRegister v3); + + // OR + inline void z_vo( VectorRegister v1, VectorRegister v2, VectorRegister v3); + + // Comparison (element-wise) + inline void z_vceq( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5); + inline void z_vceqb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vceqh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vceqf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vceqg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vceqbs( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vceqhs( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vceqfs( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vceqgs( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vch( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5); + inline void z_vchb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchbs( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchhs( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchfs( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchgs( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5); + inline void z_vchlb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchlh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchlf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchlg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchlbs( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchlhs( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchlfs( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vchlgs( VectorRegister v1, VectorRegister v2, VectorRegister v3); + + // Max/Min (element-wise) + inline void z_vmx( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmxb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmxh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmxf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmxg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmxl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmxlb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmxlh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmxlf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmxlg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmn( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmnb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmnh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmnf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmng( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmnl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmnlb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmnlh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmnlf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmnlg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + + // Leading/Trailing Zeros, population count + inline void z_vclz( VectorRegister v1, VectorRegister v2, int64_t m3); + inline void z_vclzb( VectorRegister v1, VectorRegister v2); + inline void z_vclzh( VectorRegister v1, VectorRegister v2); + inline void z_vclzf( VectorRegister v1, VectorRegister v2); + inline void z_vclzg( VectorRegister v1, VectorRegister v2); + inline void z_vctz( VectorRegister v1, VectorRegister v2, int64_t m3); + inline void z_vctzb( VectorRegister v1, VectorRegister v2); + inline void z_vctzh( VectorRegister v1, VectorRegister v2); + inline void z_vctzf( VectorRegister v1, VectorRegister v2); + inline void z_vctzg( VectorRegister v1, VectorRegister v2); + inline void z_vpopct( VectorRegister v1, VectorRegister v2, int64_t m3); + + // Rotate/Shift + inline void z_verllv( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_verllvb(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_verllvh(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_verllvf(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_verllvg(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_verll( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2, int64_t m4); + inline void z_verllb( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_verllh( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_verllf( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_verllg( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_verim( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t m5); + inline void z_verimb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4); + inline void z_verimh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4); + inline void z_verimf( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4); + inline void z_verimg( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4); + + inline void z_veslv( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_veslvb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_veslvh( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_veslvf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_veslvg( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vesl( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2, int64_t m4); + inline void z_veslb( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_veslh( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_veslf( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_veslg( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + + inline void z_vesrav( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vesravb(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vesravh(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vesravf(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vesravg(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vesra( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2, int64_t m4); + inline void z_vesrab( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_vesrah( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_vesraf( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_vesrag( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_vesrlv( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vesrlvb(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vesrlvh(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vesrlvf(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vesrlvg(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vesrl( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2, int64_t m4); + inline void z_vesrlb( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_vesrlh( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_vesrlf( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + inline void z_vesrlg( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); + + inline void z_vsl( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vslb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vsldb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4); + + inline void z_vsra( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vsrab( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vsrl( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vsrlb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + + // Test under Mask + inline void z_vtm( VectorRegister v1, VectorRegister v2); + + //---< Vector String Instructions >--- + inline void z_vfae( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5); // Find any element + inline void z_vfaeb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5); + inline void z_vfaeh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5); + inline void z_vfaef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5); + inline void z_vfee( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5); // Find element equal + inline void z_vfeeb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5); + inline void z_vfeeh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5); + inline void z_vfeef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5); + inline void z_vfene( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5); // Find element not equal + inline void z_vfeneb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5); + inline void z_vfeneh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5); + inline void z_vfenef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5); + inline void z_vstrc( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t imm5, int64_t cc6); // String range compare + inline void z_vstrcb( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6); + inline void z_vstrch( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6); + inline void z_vstrcf( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6); + inline void z_vistr( VectorRegister v1, VectorRegister v2, int64_t imm3, int64_t cc5); // Isolate String + inline void z_vistrb( VectorRegister v1, VectorRegister v2, int64_t cc5); + inline void z_vistrh( VectorRegister v1, VectorRegister v2, int64_t cc5); + inline void z_vistrf( VectorRegister v1, VectorRegister v2, int64_t cc5); + inline void z_vistrbs(VectorRegister v1, VectorRegister v2); + inline void z_vistrhs(VectorRegister v1, VectorRegister v2); + inline void z_vistrfs(VectorRegister v1, VectorRegister v2); + + // Floatingpoint instructions // ========================== @@ -2331,7 +3034,6 @@ class Assembler : public AbstractAssembler { inline void z_ahhlr(Register r1, Register r2, Register r3); // ADD halfword high low inline void z_tam(); - inline void z_stck(int64_t d2, Register b2); inline void z_stckf(int64_t d2, Register b2); inline void z_stmg(Register r1, Register r3, int64_t d2, Register b2); inline void z_lmg(Register r1, Register r3, int64_t d2, Register b2); diff --git a/src/hotspot/cpu/s390/assembler_s390.inline.hpp b/src/hotspot/cpu/s390/assembler_s390.inline.hpp index 449d0af0bf3..19c472787c5 100644 --- a/src/hotspot/cpu/s390/assembler_s390.inline.hpp +++ b/src/hotspot/cpu/s390/assembler_s390.inline.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 SAP SE. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017 SAP SE. 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 @@ -309,6 +309,9 @@ inline void Assembler::z_lcgfr(Register r1, Register r2) { emit_32( LCGFR_ZOPC | inline void Assembler::z_lnr( Register r1, Register r2) { emit_16( LNR_ZOPC | regt( r1, 8, 16) | reg((r2 == noreg) ? r1:r2, 12, 16)); } inline void Assembler::z_lngr( Register r1, Register r2) { emit_32( LNGR_ZOPC | regt( r1, 24, 32) | reg((r2 == noreg) ? r1:r2, 28, 32)); } inline void Assembler::z_lngfr(Register r1, Register r2) { emit_32( LNGFR_ZOPC | regt( r1, 24, 32) | reg((r2 == noreg) ? r1:r2, 28, 32)); } +inline void Assembler::z_lpr( Register r1, Register r2) { emit_16( LPR_ZOPC | regt( r1, 8, 16) | reg((r2 == noreg) ? r1:r2, 12, 16)); } +inline void Assembler::z_lpgr( Register r1, Register r2) { emit_32( LPGR_ZOPC | regt( r1, 24, 32) | reg((r2 == noreg) ? r1:r2, 28, 32)); } +inline void Assembler::z_lpgfr(Register r1, Register r2) { emit_32( LPGFR_ZOPC | regt( r1, 24, 32) | reg((r2 == noreg) ? r1:r2, 28, 32)); } inline void Assembler::z_lrvr( Register r1, Register r2) { emit_32( LRVR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } inline void Assembler::z_lrvgr(Register r1, Register r2) { emit_32( LRVGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } @@ -686,7 +689,6 @@ inline void Assembler::z_ahhhr(Register r1, Register r2, Register r3) { emit_32( inline void Assembler::z_ahhlr(Register r1, Register r2, Register r3) { emit_32( AHHLR_ZOPC | reg(r3, 16, 32) | reg(r1, 24, 32) | reg(r2, 28, 32)); } inline void Assembler::z_tam() { emit_16( TAM_ZOPC); } -inline void Assembler::z_stck(int64_t d2, Register b2) { emit_32( STCK_ZOPC | uimm12(d2, 20, 32) | regz(b2, 16, 32)); } inline void Assembler::z_stckf(int64_t d2, Register b2) { emit_32( STCKF_ZOPC | uimm12(d2, 20, 32) | regz(b2, 16, 32)); } inline void Assembler::z_stmg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( STMG_ZOPC | simm20(d2) | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) ); } inline void Assembler::z_lmg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( LMG_ZOPC | simm20(d2) | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) ); } @@ -702,6 +704,421 @@ inline void Assembler::z_cvd(Register r1, int64_t d2, Register x2, Register b2) inline void Assembler::z_cvdg(Register r1, int64_t d2, Register x2, Register b2) { emit_48( CVDG_ZOPC | regt(r1, 8, 48) | reg(x2, 12, 48) | reg(b2, 16, 48) | simm20(d2)); } +//--------------------------- +//-- Vector Instructions -- +//--------------------------- + +//---< Vector Support Instructions >--- + +// Load (transfer from memory) +inline void Assembler::z_vlm( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {emit_48(VLM_ZOPC | vreg(v1, 8) | vreg(v3, 12) | rsmask_48(d2, b2)); } +inline void Assembler::z_vl( VectorRegister v1, int64_t d2, Register x2, Register b2) {emit_48(VL_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2)); } +inline void Assembler::z_vleb( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3) {emit_48(VLEB_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | veix_mask(m3, VRET_BYTE, 32)); } +inline void Assembler::z_vleh( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3) {emit_48(VLEH_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | veix_mask(m3, VRET_HW, 32)); } +inline void Assembler::z_vlef( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3) {emit_48(VLEF_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | veix_mask(m3, VRET_FW, 32)); } +inline void Assembler::z_vleg( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3) {emit_48(VLEG_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | veix_mask(m3, VRET_DW, 32)); } + +// Gather/Scatter +inline void Assembler::z_vgef( VectorRegister v1, int64_t d2, VectorRegister vx2, Register b2, int64_t m3) {emit_48(VGEF_ZOPC | vreg(v1, 8) | rvmask_48(d2, vx2, b2) | veix_mask(m3, VRET_FW, 32)); } +inline void Assembler::z_vgeg( VectorRegister v1, int64_t d2, VectorRegister vx2, Register b2, int64_t m3) {emit_48(VGEG_ZOPC | vreg(v1, 8) | rvmask_48(d2, vx2, b2) | veix_mask(m3, VRET_DW, 32)); } + +inline void Assembler::z_vscef( VectorRegister v1, int64_t d2, VectorRegister vx2, Register b2, int64_t m3) {emit_48(VSCEF_ZOPC | vreg(v1, 8) | rvmask_48(d2, vx2, b2) | veix_mask(m3, VRET_FW, 32)); } +inline void Assembler::z_vsceg( VectorRegister v1, int64_t d2, VectorRegister vx2, Register b2, int64_t m3) {emit_48(VSCEG_ZOPC | vreg(v1, 8) | rvmask_48(d2, vx2, b2) | veix_mask(m3, VRET_DW, 32)); } + +// load and replicate +inline void Assembler::z_vlrep( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3) {emit_48(VLREP_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | vesc_mask(m3, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vlrepb( VectorRegister v1, int64_t d2, Register x2, Register b2) {z_vlrep(v1, d2, x2, b2, VRET_BYTE); }// load byte and replicate to all vector elements of type 'B' +inline void Assembler::z_vlreph( VectorRegister v1, int64_t d2, Register x2, Register b2) {z_vlrep(v1, d2, x2, b2, VRET_HW); } // load HW and replicate to all vector elements of type 'H' +inline void Assembler::z_vlrepf( VectorRegister v1, int64_t d2, Register x2, Register b2) {z_vlrep(v1, d2, x2, b2, VRET_FW); } // load FW and replicate to all vector elements of type 'F' +inline void Assembler::z_vlrepg( VectorRegister v1, int64_t d2, Register x2, Register b2) {z_vlrep(v1, d2, x2, b2, VRET_DW); } // load DW and replicate to all vector elements of type 'G' + +inline void Assembler::z_vllez( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3) {emit_48(VLLEZ_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | vesc_mask(m3, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vllezb( VectorRegister v1, int64_t d2, Register x2, Register b2) {z_vllez(v1, d2, x2, b2, VRET_BYTE); }// load logical byte into left DW of VR, zero all other bit positions. +inline void Assembler::z_vllezh( VectorRegister v1, int64_t d2, Register x2, Register b2) {z_vllez(v1, d2, x2, b2, VRET_HW); } // load logical HW into left DW of VR, zero all other bit positions. +inline void Assembler::z_vllezf( VectorRegister v1, int64_t d2, Register x2, Register b2) {z_vllez(v1, d2, x2, b2, VRET_FW); } // load logical FW into left DW of VR, zero all other bit positions. +inline void Assembler::z_vllezg( VectorRegister v1, int64_t d2, Register x2, Register b2) {z_vllez(v1, d2, x2, b2, VRET_DW); } // load logical DW into left DW of VR, zero all other bit positions. + +inline void Assembler::z_vlbb( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3) {emit_48(VLBB_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | uimm4(m3, 32, 48)); } +inline void Assembler::z_vll( VectorRegister v1, Register r3, int64_t d2, Register b2) {emit_48(VLL_ZOPC | vreg(v1, 8) | reg(r3, 12, 48) | rsmask_48(d2, b2)); } + +// Load (register to register) +inline void Assembler::z_vlr ( VectorRegister v1, VectorRegister v2) {emit_48(VLR_ZOPC | vreg(v1, 8) | vreg(v2, 12)); } + +inline void Assembler::z_vlgv( Register r1, VectorRegister v3, int64_t d2, Register b2, int64_t m4) {emit_48(VLGV_ZOPC | reg(r1, 8, 48) | vreg(v3, 12) | rsmask_48(d2, b2) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vlgvb( Register r1, VectorRegister v3, int64_t d2, Register b2) {z_vlgv(r1, v3, d2, b2, VRET_BYTE); } // load byte from VR element (index d2(b2)) into GR (logical) +inline void Assembler::z_vlgvh( Register r1, VectorRegister v3, int64_t d2, Register b2) {z_vlgv(r1, v3, d2, b2, VRET_HW); } // load HW from VR element (index d2(b2)) into GR (logical) +inline void Assembler::z_vlgvf( Register r1, VectorRegister v3, int64_t d2, Register b2) {z_vlgv(r1, v3, d2, b2, VRET_FW); } // load FW from VR element (index d2(b2)) into GR (logical) +inline void Assembler::z_vlgvg( Register r1, VectorRegister v3, int64_t d2, Register b2) {z_vlgv(r1, v3, d2, b2, VRET_DW); } // load DW from VR element (index d2(b2)) into GR. + +inline void Assembler::z_vlvg( VectorRegister v1, Register r3, int64_t d2, Register b2, int64_t m4) {emit_48(VLVG_ZOPC | vreg(v1, 8) | reg(r3, 12, 48) | rsmask_48(d2, b2) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vlvgb( VectorRegister v1, Register r3, int64_t d2, Register b2) {z_vlvg(v1, r3, d2, b2, VRET_BYTE); } +inline void Assembler::z_vlvgh( VectorRegister v1, Register r3, int64_t d2, Register b2) {z_vlvg(v1, r3, d2, b2, VRET_HW); } +inline void Assembler::z_vlvgf( VectorRegister v1, Register r3, int64_t d2, Register b2) {z_vlvg(v1, r3, d2, b2, VRET_FW); } +inline void Assembler::z_vlvgg( VectorRegister v1, Register r3, int64_t d2, Register b2) {z_vlvg(v1, r3, d2, b2, VRET_DW); } + +inline void Assembler::z_vlvgp( VectorRegister v1, Register r2, Register r3) {emit_48(VLVGP_ZOPC | vreg(v1, 8) | reg(r2, 12, 48) | reg(r3, 16, 48)); } + +// vector register pack +inline void Assembler::z_vpk( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VPK_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_HW, VRET_DW, 32)); } +inline void Assembler::z_vpkh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpk(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vpkf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpk(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vpkg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpk(v1, v2, v3, VRET_DW); } // vector element type 'G' + +inline void Assembler::z_vpks( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VPKS_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_HW, VRET_DW, 32) | voprc_ccmask(cc5, 24)); } +inline void Assembler::z_vpksh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC +inline void Assembler::z_vpksf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC +inline void Assembler::z_vpksg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC +inline void Assembler::z_vpkshs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', set CC +inline void Assembler::z_vpksfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', set CC +inline void Assembler::z_vpksgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', set CC + +inline void Assembler::z_vpkls( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VPKLS_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_HW, VRET_DW, 32) | voprc_ccmask(cc5, 24)); } +inline void Assembler::z_vpklsh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC +inline void Assembler::z_vpklsf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC +inline void Assembler::z_vpklsg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC +inline void Assembler::z_vpklshs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', set CC +inline void Assembler::z_vpklsfs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', set CC +inline void Assembler::z_vpklsgs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', set CC + +// vector register unpack (sign-extended) +inline void Assembler::z_vuph( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VUPH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m3, VRET_BYTE, VRET_FW, 32)); } +inline void Assembler::z_vuphb( VectorRegister v1, VectorRegister v2) {z_vuph(v1, v2, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vuphh( VectorRegister v1, VectorRegister v2) {z_vuph(v1, v2, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vuphf( VectorRegister v1, VectorRegister v2) {z_vuph(v1, v2, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vupl( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VUPL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m3, VRET_BYTE, VRET_FW, 32)); } +inline void Assembler::z_vuplb( VectorRegister v1, VectorRegister v2) {z_vupl(v1, v2, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vuplh( VectorRegister v1, VectorRegister v2) {z_vupl(v1, v2, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vuplf( VectorRegister v1, VectorRegister v2) {z_vupl(v1, v2, VRET_FW); } // vector element type 'F' + +// vector register unpack (zero-extended) +inline void Assembler::z_vuplh( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VUPLH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m3, VRET_BYTE, VRET_FW, 32)); } +inline void Assembler::z_vuplhb( VectorRegister v1, VectorRegister v2) {z_vuplh(v1, v2, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vuplhh( VectorRegister v1, VectorRegister v2) {z_vuplh(v1, v2, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vuplhf( VectorRegister v1, VectorRegister v2) {z_vuplh(v1, v2, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vupll( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VUPLL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m3, VRET_BYTE, VRET_FW, 32)); } +inline void Assembler::z_vupllb( VectorRegister v1, VectorRegister v2) {z_vupll(v1, v2, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vupllh( VectorRegister v1, VectorRegister v2) {z_vupll(v1, v2, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vupllf( VectorRegister v1, VectorRegister v2) {z_vupll(v1, v2, VRET_FW); } // vector element type 'F' + +// vector register merge high/low +inline void Assembler::z_vmrh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMRH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vmrhb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmrh(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vmrhh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmrh(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vmrhf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmrh(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vmrhg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmrh(v1, v2, v3, VRET_DW); } // vector element type 'G' + +inline void Assembler::z_vmrl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMRL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vmrlb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmrh(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vmrlh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmrh(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vmrlf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmrh(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vmrlg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmrh(v1, v2, v3, VRET_DW); } // vector element type 'G' + +// vector register permute +inline void Assembler::z_vperm( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4) {emit_48(VPERM_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vreg(v4, 32)); } +inline void Assembler::z_vpdi( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VPDI_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | uimm4(m4, 32, 48)); } + +// vector register replicate +inline void Assembler::z_vrep( VectorRegister v1, VectorRegister v3, int64_t imm2, int64_t m4) {emit_48(VREP_ZOPC | vreg(v1, 8) | vreg(v3, 12) | simm16(imm2, 16, 48) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vrepb( VectorRegister v1, VectorRegister v3, int64_t imm2) {z_vrep(v1, v3, imm2, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vreph( VectorRegister v1, VectorRegister v3, int64_t imm2) {z_vrep(v1, v3, imm2, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vrepf( VectorRegister v1, VectorRegister v3, int64_t imm2) {z_vrep(v1, v3, imm2, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vrepg( VectorRegister v1, VectorRegister v3, int64_t imm2) {z_vrep(v1, v3, imm2, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vrepi( VectorRegister v1, int64_t imm2, int64_t m3) {emit_48(VREPI_ZOPC | vreg(v1, 8) | simm16(imm2, 16, 48) | vesc_mask(m3, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vrepib( VectorRegister v1, int64_t imm2) {z_vrepi(v1, imm2, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vrepih( VectorRegister v1, int64_t imm2) {z_vrepi(v1, imm2, VRET_HW); } // vector element type 'B' +inline void Assembler::z_vrepif( VectorRegister v1, int64_t imm2) {z_vrepi(v1, imm2, VRET_FW); } // vector element type 'B' +inline void Assembler::z_vrepig( VectorRegister v1, int64_t imm2) {z_vrepi(v1, imm2, VRET_DW); } // vector element type 'B' + +inline void Assembler::z_vsel( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4) {emit_48(VSEL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vreg(v4, 32)); } +inline void Assembler::z_vseg( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VSEG_ZOPC | vreg(v1, 8) | vreg(v2, 12) | uimm4(m3, 32, 48)); } + +// Load (immediate) +inline void Assembler::z_vleib( VectorRegister v1, int64_t imm2, int64_t m3) {emit_48(VLEIB_ZOPC | vreg(v1, 8) | simm16(imm2, 32, 48) | veix_mask(m3, VRET_BYTE, 32)); } +inline void Assembler::z_vleih( VectorRegister v1, int64_t imm2, int64_t m3) {emit_48(VLEIH_ZOPC | vreg(v1, 8) | simm16(imm2, 32, 48) | veix_mask(m3, VRET_HW, 32)); } +inline void Assembler::z_vleif( VectorRegister v1, int64_t imm2, int64_t m3) {emit_48(VLEIF_ZOPC | vreg(v1, 8) | simm16(imm2, 32, 48) | veix_mask(m3, VRET_FW, 32)); } +inline void Assembler::z_vleig( VectorRegister v1, int64_t imm2, int64_t m3) {emit_48(VLEIG_ZOPC | vreg(v1, 8) | simm16(imm2, 32, 48) | veix_mask(m3, VRET_DW, 32)); } + +// Store +inline void Assembler::z_vstm( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {emit_48(VSTM_ZOPC | vreg(v1, 8) | vreg(v3, 12) | rsmask_48(d2, b2)); } +inline void Assembler::z_vst( VectorRegister v1, int64_t d2, Register x2, Register b2) {emit_48(VST_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2)); } +inline void Assembler::z_vsteb( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3) {emit_48(VSTEB_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | veix_mask(m3, VRET_BYTE, 32)); } +inline void Assembler::z_vsteh( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3) {emit_48(VSTEH_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | veix_mask(m3, VRET_HW, 32)); } +inline void Assembler::z_vstef( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3) {emit_48(VSTEF_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | veix_mask(m3, VRET_FW, 32)); } +inline void Assembler::z_vsteg( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3) {emit_48(VSTEG_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | veix_mask(m3, VRET_DW, 32)); } +inline void Assembler::z_vstl( VectorRegister v1, Register r3, int64_t d2, Register b2) {emit_48(VSTL_ZOPC | vreg(v1, 8) | reg(r3, 12, 48) | rsmask_48(d2, b2)); } + +// Misc +inline void Assembler::z_vgm( VectorRegister v1, int64_t imm2, int64_t imm3, int64_t m4) {emit_48(VGM_ZOPC | vreg(v1, 8) | uimm8( imm2, 16, 48) | uimm8(imm3, 24, 48) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vgmb( VectorRegister v1, int64_t imm2, int64_t imm3) {z_vgm(v1, imm2, imm3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vgmh( VectorRegister v1, int64_t imm2, int64_t imm3) {z_vgm(v1, imm2, imm3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vgmf( VectorRegister v1, int64_t imm2, int64_t imm3) {z_vgm(v1, imm2, imm3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vgmg( VectorRegister v1, int64_t imm2, int64_t imm3) {z_vgm(v1, imm2, imm3, VRET_DW); } // vector element type 'G' + +inline void Assembler::z_vgbm( VectorRegister v1, int64_t imm2) {emit_48(VGBM_ZOPC | vreg(v1, 8) | uimm16(imm2, 16, 48)); } +inline void Assembler::z_vzero( VectorRegister v1) {z_vgbm(v1, 0); } // preferred method to set vreg to all zeroes +inline void Assembler::z_vone( VectorRegister v1) {z_vgbm(v1, 0xffff); } // preferred method to set vreg to all ones + +//---< Vector Arithmetic Instructions >--- + +// Load +inline void Assembler::z_vlc( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VLC_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m3, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vlcb( VectorRegister v1, VectorRegister v2) {z_vlc(v1, v2, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vlch( VectorRegister v1, VectorRegister v2) {z_vlc(v1, v2, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vlcf( VectorRegister v1, VectorRegister v2) {z_vlc(v1, v2, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vlcg( VectorRegister v1, VectorRegister v2) {z_vlc(v1, v2, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vlp( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VLP_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m3, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vlpb( VectorRegister v1, VectorRegister v2) {z_vlp(v1, v2, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vlph( VectorRegister v1, VectorRegister v2) {z_vlp(v1, v2, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vlpf( VectorRegister v1, VectorRegister v2) {z_vlp(v1, v2, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vlpg( VectorRegister v1, VectorRegister v2) {z_vlp(v1, v2, VRET_DW); } // vector element type 'G' + +// ADD +inline void Assembler::z_va( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VA_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_QW, 32)); } +inline void Assembler::z_vab( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_va(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vah( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_va(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vaf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_va(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vag( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_va(v1, v2, v3, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vaq( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_va(v1, v2, v3, VRET_QW); } // vector element type 'Q' +inline void Assembler::z_vacc( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VACC_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_QW, 32)); } +inline void Assembler::z_vaccb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vacc(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vacch( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vacc(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vaccf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vacc(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vaccg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vacc(v1, v2, v3, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vaccq( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vacc(v1, v2, v3, VRET_QW); } // vector element type 'Q' + +// SUB +inline void Assembler::z_vs( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VS_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_QW, 32)); } +inline void Assembler::z_vsb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vs(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vsh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vs(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vsf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vs(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vsg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vs(v1, v2, v3, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vsq( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vs(v1, v2, v3, VRET_QW); } // vector element type 'Q' +inline void Assembler::z_vscbi( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VSCBI_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_QW, 32)); } +inline void Assembler::z_vscbib( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vscbi(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vscbih( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vscbi(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vscbif( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vscbi(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vscbig( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vscbi(v1, v2, v3, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vscbiq( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vscbi(v1, v2, v3, VRET_QW); } // vector element type 'Q' + +// MULTIPLY +inline void Assembler::z_vml( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VML_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_FW, 32)); } +inline void Assembler::z_vmh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_FW, 32)); } +inline void Assembler::z_vmlh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMLH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_FW, 32)); } +inline void Assembler::z_vme( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VME_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_FW, 32)); } +inline void Assembler::z_vmle( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMLE_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_FW, 32)); } +inline void Assembler::z_vmo( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMO_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_FW, 32)); } +inline void Assembler::z_vmlo( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMLO_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_FW, 32)); } + +// MULTIPLY & ADD +inline void Assembler::z_vmal( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5) {emit_48(VMAL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vreg(v4, 32) | vesc_mask(m5, VRET_BYTE, VRET_FW, 20)); } +inline void Assembler::z_vmah( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5) {emit_48(VMAH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vreg(v4, 32) | vesc_mask(m5, VRET_BYTE, VRET_FW, 20)); } +inline void Assembler::z_vmalh( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5) {emit_48(VMALH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vreg(v4, 32) | vesc_mask(m5, VRET_BYTE, VRET_FW, 20)); } +inline void Assembler::z_vmae( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5) {emit_48(VMAE_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vreg(v4, 32) | vesc_mask(m5, VRET_BYTE, VRET_FW, 20)); } +inline void Assembler::z_vmale( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5) {emit_48(VMALE_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vreg(v4, 32) | vesc_mask(m5, VRET_BYTE, VRET_FW, 20)); } +inline void Assembler::z_vmao( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5) {emit_48(VMAO_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vreg(v4, 32) | vesc_mask(m5, VRET_BYTE, VRET_FW, 20)); } +inline void Assembler::z_vmalo( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5) {emit_48(VMALO_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vreg(v4, 32) | vesc_mask(m5, VRET_BYTE, VRET_FW, 20)); } + +// VECTOR SUM +inline void Assembler::z_vsum( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VSUM_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_HW, 32)); } +inline void Assembler::z_vsumb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vsum(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vsumh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vsum(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vsumg( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VSUMG_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_HW, VRET_FW, 32)); } +inline void Assembler::z_vsumgh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vsumg(v1, v2, v3, VRET_HW); } // vector element type 'B' +inline void Assembler::z_vsumgf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vsumg(v1, v2, v3, VRET_FW); } // vector element type 'H' +inline void Assembler::z_vsumq( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VSUMQ_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_FW, VRET_DW, 32)); } +inline void Assembler::z_vsumqf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vsumq(v1, v2, v3, VRET_FW); } // vector element type 'B' +inline void Assembler::z_vsumqg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vsumq(v1, v2, v3, VRET_DW); } // vector element type 'H' + +// Average +inline void Assembler::z_vavg( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VAVG_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vavgb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vavg(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vavgh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vavg(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vavgf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vavg(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vavgg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vavg(v1, v2, v3, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vavgl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VAVGL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vavglb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vavgl(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vavglh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vavgl(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vavglf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vavgl(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vavglg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vavgl(v1, v2, v3, VRET_DW); } // vector element type 'G' + +// VECTOR Galois Field Multiply Sum +inline void Assembler::z_vgfm( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VGFM_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vgfmb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vgfm(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vgfmh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vgfm(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vgfmf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vgfm(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vgfmg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vgfm(v1, v2, v3, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vgfma( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5) {emit_48(VGFMA_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vreg(v3, 16) | vesc_mask(m5, VRET_BYTE, VRET_DW, 20)); } +inline void Assembler::z_vgfmab( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4) {z_vgfma(v1, v2, v3, v4, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vgfmah( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4) {z_vgfma(v1, v2, v3, v4, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vgfmaf( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4) {z_vgfma(v1, v2, v3, v4, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vgfmag( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4) {z_vgfma(v1, v2, v3, v4, VRET_DW); } // vector element type 'G' + +//---< Vector Logical Instructions >--- + +// AND +inline void Assembler::z_vn( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VN_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } +inline void Assembler::z_vnc( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VNC_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } + +// XOR +inline void Assembler::z_vx( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VX_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } + +// NOR +inline void Assembler::z_vno( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VNO_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } + +// OR +inline void Assembler::z_vo( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VO_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } + +// Comparison (element-wise) +inline void Assembler::z_vceq( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCEQ_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | voprc_ccmask(cc5, 24)); } +inline void Assembler::z_vceqb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_BYTE, VOPRC_CCIGN); } // vector element type 'B', don't set CC +inline void Assembler::z_vceqh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC +inline void Assembler::z_vceqf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC +inline void Assembler::z_vceqg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC +inline void Assembler::z_vceqbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_BYTE, VOPRC_CCSET); } // vector element type 'B', don't set CC +inline void Assembler::z_vceqhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', don't set CC +inline void Assembler::z_vceqfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', don't set CC +inline void Assembler::z_vceqgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', don't set CC +inline void Assembler::z_vch( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | voprc_ccmask(cc5, 24)); } +inline void Assembler::z_vchb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_BYTE, VOPRC_CCIGN); } // vector element type 'B', don't set CC +inline void Assembler::z_vchh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC +inline void Assembler::z_vchf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC +inline void Assembler::z_vchg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC +inline void Assembler::z_vchbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_BYTE, VOPRC_CCSET); } // vector element type 'B', don't set CC +inline void Assembler::z_vchhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', don't set CC +inline void Assembler::z_vchfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', don't set CC +inline void Assembler::z_vchgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', don't set CC +inline void Assembler::z_vchl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCHL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | voprc_ccmask(cc5, 24)); } +inline void Assembler::z_vchlb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_BYTE, VOPRC_CCIGN); } // vector element type 'B', don't set CC +inline void Assembler::z_vchlh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC +inline void Assembler::z_vchlf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC +inline void Assembler::z_vchlg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC +inline void Assembler::z_vchlbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_BYTE, VOPRC_CCSET); } // vector element type 'B', don't set CC +inline void Assembler::z_vchlhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', don't set CC +inline void Assembler::z_vchlfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', don't set CC +inline void Assembler::z_vchlgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', don't set CC + +// Max/Min (element-wise) +inline void Assembler::z_vmx( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMX_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vmxb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmx(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vmxh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmx(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vmxf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmx(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vmxg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmx(v1, v2, v3, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vmxl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMXL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vmxlb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmxl(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vmxlh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmxl(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vmxlf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmxl(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vmxlg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmxl(v1, v2, v3, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vmn( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMN_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vmnb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmn(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vmnh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmn(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vmnf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmn(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vmng( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmn(v1, v2, v3, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vmnl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMNL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vmnlb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmnl(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vmnlh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmnl(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vmnlf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmnl(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vmnlg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vmnl(v1, v2, v3, VRET_DW); } // vector element type 'G' + +// Leading/Trailing Zeros, population count +inline void Assembler::z_vclz( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VCLZ_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m3, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vclzb( VectorRegister v1, VectorRegister v2) {z_vclz(v1, v2, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vclzh( VectorRegister v1, VectorRegister v2) {z_vclz(v1, v2, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vclzf( VectorRegister v1, VectorRegister v2) {z_vclz(v1, v2, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vclzg( VectorRegister v1, VectorRegister v2) {z_vclz(v1, v2, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vctz( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VCTZ_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m3, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vctzb( VectorRegister v1, VectorRegister v2) {z_vctz(v1, v2, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vctzh( VectorRegister v1, VectorRegister v2) {z_vctz(v1, v2, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vctzf( VectorRegister v1, VectorRegister v2) {z_vctz(v1, v2, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vctzg( VectorRegister v1, VectorRegister v2) {z_vctz(v1, v2, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vpopct( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VPOPCT_ZOPC| vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m3, VRET_BYTE, VRET_DW, 32)); } + +// Rotate/Shift +inline void Assembler::z_verllv( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VERLLV_ZOPC| vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_verllvb(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_verllv(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_verllvh(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_verllv(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_verllvf(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_verllv(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_verllvg(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_verllv(v1, v2, v3, VRET_DW); } // vector element type 'G' +inline void Assembler::z_verll( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2, int64_t m4) {emit_48(VERLL_ZOPC | vreg(v1, 8) | vreg(v3, 12) | rsmask_48(d2, b2) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_verllb( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_verll(v1, v3, d2, b2, VRET_BYTE);}// vector element type 'B' +inline void Assembler::z_verllh( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_verll(v1, v3, d2, b2, VRET_HW);} // vector element type 'H' +inline void Assembler::z_verllf( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_verll(v1, v3, d2, b2, VRET_FW);} // vector element type 'F' +inline void Assembler::z_verllg( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_verll(v1, v3, d2, b2, VRET_DW);} // vector element type 'G' +inline void Assembler::z_verim( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t m5) {emit_48(VERLL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | uimm8(imm4, 24, 48) | vesc_mask(m5, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_verimb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4) {z_verim(v1, v2, v3, imm4, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_verimh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4) {z_verim(v1, v2, v3, imm4, VRET_HW); } // vector element type 'H' +inline void Assembler::z_verimf( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4) {z_verim(v1, v2, v3, imm4, VRET_FW); } // vector element type 'F' +inline void Assembler::z_verimg( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4) {z_verim(v1, v2, v3, imm4, VRET_DW); } // vector element type 'G' + +inline void Assembler::z_veslv( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VESLV_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_veslvb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_veslv(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_veslvh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_veslv(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_veslvf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_veslv(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_veslvg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_veslv(v1, v2, v3, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vesl( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2, int64_t m4) {emit_48(VESL_ZOPC | vreg(v1, 8) | vreg(v3, 12) | rsmask_48(d2, b2) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_veslb( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_vesl(v1, v3, d2, b2, VRET_BYTE);} // vector element type 'B' +inline void Assembler::z_veslh( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_vesl(v1, v3, d2, b2, VRET_HW);} // vector element type 'H' +inline void Assembler::z_veslf( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_vesl(v1, v3, d2, b2, VRET_FW);} // vector element type 'F' +inline void Assembler::z_veslg( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_vesl(v1, v3, d2, b2, VRET_DW);} // vector element type 'G' + +inline void Assembler::z_vesrav( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VESRAV_ZOPC| vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vesravb(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vesrav(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vesravh(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vesrav(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vesravf(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vesrav(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vesravg(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vesrav(v1, v2, v3, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vesra( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2, int64_t m4) {emit_48(VESRA_ZOPC | vreg(v1, 8) | vreg(v3, 12) | rsmask_48(d2, b2) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vesrab( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_vesra(v1, v3, d2, b2, VRET_BYTE);}// vector element type 'B' +inline void Assembler::z_vesrah( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_vesra(v1, v3, d2, b2, VRET_HW);} // vector element type 'H' +inline void Assembler::z_vesraf( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_vesra(v1, v3, d2, b2, VRET_FW);} // vector element type 'F' +inline void Assembler::z_vesrag( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_vesra(v1, v3, d2, b2, VRET_DW);} // vector element type 'G' +inline void Assembler::z_vesrlv( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VESRLV_ZOPC| vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vesrlvb(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vesrlv(v1, v2, v3, VRET_BYTE); } // vector element type 'B' +inline void Assembler::z_vesrlvh(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vesrlv(v1, v2, v3, VRET_HW); } // vector element type 'H' +inline void Assembler::z_vesrlvf(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vesrlv(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vesrlvg(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vesrlv(v1, v2, v3, VRET_DW); } // vector element type 'G' +inline void Assembler::z_vesrl( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2, int64_t m4) {emit_48(VESRL_ZOPC | vreg(v1, 8) | vreg(v3, 12) | rsmask_48(d2, b2) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vesrlb( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_vesrl(v1, v3, d2, b2, VRET_BYTE);}// vector element type 'B' +inline void Assembler::z_vesrlh( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_vesrl(v1, v3, d2, b2, VRET_HW);} // vector element type 'H' +inline void Assembler::z_vesrlf( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_vesrl(v1, v3, d2, b2, VRET_FW);} // vector element type 'F' +inline void Assembler::z_vesrlg( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_vesrl(v1, v3, d2, b2, VRET_DW);} // vector element type 'G' + +inline void Assembler::z_vsl( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VSL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } +inline void Assembler::z_vslb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VSLB_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } +inline void Assembler::z_vsldb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4) {emit_48(VSLDB_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | uimm8(imm4, 24, 48)); } + +inline void Assembler::z_vsra( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VSRA_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } +inline void Assembler::z_vsrab( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VSRAB_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } +inline void Assembler::z_vsrl( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VSRL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } +inline void Assembler::z_vsrlb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VSRLB_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } + +// Test under Mask +inline void Assembler::z_vtm( VectorRegister v1, VectorRegister v2) {emit_48(VTM_ZOPC | vreg(v1, 8) | vreg(v2, 12)); } + +//---< Vector String Instructions >--- +inline void Assembler::z_vfae( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5) {emit_48(VFAE_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(imm4, VRET_BYTE, VRET_FW, 32) | voprc_any(cc5, 24) ); } // Find any element +inline void Assembler::z_vfaeb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfae(v1, v2, v3, VRET_BYTE, cc5); } +inline void Assembler::z_vfaeh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfae(v1, v2, v3, VRET_HW, cc5); } +inline void Assembler::z_vfaef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfae(v1, v2, v3, VRET_FW, cc5); } +inline void Assembler::z_vfee( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5) {emit_48(VFEE_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(imm4, VRET_BYTE, VRET_FW, 32) | voprc_any(cc5, 24) ); } // Find element equal +inline void Assembler::z_vfeeb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfee(v1, v2, v3, VRET_BYTE, cc5); } +inline void Assembler::z_vfeeh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfee(v1, v2, v3, VRET_HW, cc5); } +inline void Assembler::z_vfeef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfee(v1, v2, v3, VRET_FW, cc5); } +inline void Assembler::z_vfene( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5) {emit_48(VFENE_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(imm4, VRET_BYTE, VRET_FW, 32) | voprc_any(cc5, 24) ); } // Find element not equal +inline void Assembler::z_vfeneb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfene(v1, v2, v3, VRET_BYTE, cc5); } +inline void Assembler::z_vfeneh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfene(v1, v2, v3, VRET_HW, cc5); } +inline void Assembler::z_vfenef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfene(v1, v2, v3, VRET_FW, cc5); } +inline void Assembler::z_vstrc( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t imm5, int64_t cc6) {emit_48(VSTRC_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vreg(v4, 32) | vesc_mask(imm5, VRET_BYTE, VRET_FW, 20) | voprc_any(cc6, 24) ); } // String range compare +inline void Assembler::z_vstrcb( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6) {z_vstrc(v1, v2, v3, v4, VRET_BYTE, cc6); } +inline void Assembler::z_vstrch( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6) {z_vstrc(v1, v2, v3, v4, VRET_HW, cc6); } +inline void Assembler::z_vstrcf( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6) {z_vstrc(v1, v2, v3, v4, VRET_FW, cc6); } +inline void Assembler::z_vistr( VectorRegister v1, VectorRegister v2, int64_t imm3, int64_t cc5) {emit_48(VISTR_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(imm3, VRET_BYTE, VRET_FW, 32) | voprc_any(cc5, 24) ); } // isolate string +inline void Assembler::z_vistrb( VectorRegister v1, VectorRegister v2, int64_t cc5) {z_vistr(v1, v2, VRET_BYTE, cc5); } +inline void Assembler::z_vistrh( VectorRegister v1, VectorRegister v2, int64_t cc5) {z_vistr(v1, v2, VRET_HW, cc5); } +inline void Assembler::z_vistrf( VectorRegister v1, VectorRegister v2, int64_t cc5) {z_vistr(v1, v2, VRET_FW, cc5); } +inline void Assembler::z_vistrbs(VectorRegister v1, VectorRegister v2) {z_vistr(v1, v2, VRET_BYTE, VOPRC_CCSET); } +inline void Assembler::z_vistrhs(VectorRegister v1, VectorRegister v2) {z_vistr(v1, v2, VRET_HW, VOPRC_CCSET); } +inline void Assembler::z_vistrfs(VectorRegister v1, VectorRegister v2) {z_vistr(v1, v2, VRET_FW, VOPRC_CCSET); } + + //------------------------------- // FLOAT INSTRUCTIONS //------------------------------- diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index 21634f930e7..caa5e942394 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -2713,13 +2713,9 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { metadata2reg(md->constant_encoding(), mdo); Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); - Bytecodes::Code bc = method->java_code_at_bci(bci); - const bool callee_is_static = callee->is_loaded() && callee->is_static(); // Perform additional virtual call profiling for invokevirtual and - // invokeinterface bytecodes. - if ((bc == Bytecodes::_invokevirtual || bc == Bytecodes::_invokeinterface) && - !callee_is_static && // Required for optimized MH invokes. - C1ProfileVirtualCalls) { + // invokeinterface bytecodes + if (op->should_profile_receiver_type()) { assert(op->recv()->is_single_cpu(), "recv must be allocated"); Register recv = op->recv()->as_register(); assert_different_registers(mdo, tmp1, recv); diff --git a/src/hotspot/cpu/s390/globals_s390.hpp b/src/hotspot/cpu/s390/globals_s390.hpp index cb5adff3ef5..fef2dbec99b 100644 --- a/src/hotspot/cpu/s390/globals_s390.hpp +++ b/src/hotspot/cpu/s390/globals_s390.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 SAP SE. All rights reserved. + * Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017 SAP SE. 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 @@ -34,7 +34,7 @@ // Sorted according to sparc. // z/Architecture remembers branch targets, so don't share vtables. -define_pd_global(bool, ShareVtableStubs, false); +define_pd_global(bool, ShareVtableStubs, true); define_pd_global(bool, NeedsDeoptSuspend, false); // Only register window machines need this. define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks. diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index 99965528886..edcbc8f4b1d 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -914,7 +914,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // // markOop displaced_header = obj->mark().set_unlocked(); // monitor->lock()->set_displaced_header(displaced_header); - // if (Atomic::cmpxchg_ptr(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) { + // if (Atomic::cmpxchg(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) { // // We stored the monitor address into the object's mark word. // } else if (THREAD->is_lock_owned((address)displaced_header)) // // Simple recursive case. @@ -949,7 +949,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { z_stg(displaced_header, BasicObjectLock::lock_offset_in_bytes() + BasicLock::displaced_header_offset_in_bytes(), monitor); - // if (Atomic::cmpxchg_ptr(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) { + // if (Atomic::cmpxchg(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) { // Store stack address of the BasicObjectLock (this is monitor) into object. add2reg(object_mark_addr, oopDesc::mark_offset_in_bytes(), object); @@ -1021,7 +1021,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, Register object) // if ((displaced_header = monitor->displaced_header()) == NULL) { // // Recursive unlock. Mark the monitor unlocked by setting the object field to NULL. // monitor->set_obj(NULL); - // } else if (Atomic::cmpxchg_ptr(displaced_header, obj->mark_addr(), monitor) == monitor) { + // } else if (Atomic::cmpxchg(displaced_header, obj->mark_addr(), monitor) == monitor) { // // We swapped the unlocked mark in displaced_header into the object's mark word. // monitor->set_obj(NULL); // } else { @@ -1062,7 +1062,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, Register object) BasicLock::displaced_header_offset_in_bytes())); z_bre(done); // displaced_header == 0 -> goto done - // } else if (Atomic::cmpxchg_ptr(displaced_header, obj->mark_addr(), monitor) == monitor) { + // } else if (Atomic::cmpxchg(displaced_header, obj->mark_addr(), monitor) == monitor) { // // We swapped the unlocked mark in displaced_header into the object's mark word. // monitor->set_obj(NULL); diff --git a/src/hotspot/cpu/s390/jniTypes_s390.hpp b/src/hotspot/cpu/s390/jniTypes_s390.hpp index de7bfb49251..a10d9699a83 100644 --- a/src/hotspot/cpu/s390/jniTypes_s390.hpp +++ b/src/hotspot/cpu/s390/jniTypes_s390.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -29,9 +29,9 @@ // This file holds platform-dependent routines used to write primitive // jni types to the array of arguments passed into JavaCalls::call. +#include "jni.h" #include "memory/allocation.hpp" #include "oops/oop.hpp" -#include "prims/jni.h" class JNITypes : AllStatic { // These functions write a java primitive type (in native format) to diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index b8d3e4de275..af2c02934ff 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -4671,6 +4671,7 @@ void MacroAssembler::load_mirror(Register mirror, Register method) { mem2reg_opt(mirror, Address(mirror, ConstMethod::constants_offset())); mem2reg_opt(mirror, Address(mirror, ConstantPool::pool_holder_offset_in_bytes())); mem2reg_opt(mirror, Address(mirror, Klass::java_mirror_offset())); + resolve_oop_handle(mirror); } //--------------------------------------------------------------- diff --git a/src/hotspot/cpu/s390/register_definitions_s390.cpp b/src/hotspot/cpu/s390/register_definitions_s390.cpp index 99116f5399b..2378d513799 100644 --- a/src/hotspot/cpu/s390/register_definitions_s390.cpp +++ b/src/hotspot/cpu/s390/register_definitions_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 SAP SE. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017 SAP SE. 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 @@ -35,3 +35,5 @@ REGISTER_DEFINITION(Register, noreg); REGISTER_DEFINITION(FloatRegister, fnoreg); + +REGISTER_DEFINITION(VectorRegister, vnoreg); diff --git a/src/hotspot/cpu/s390/register_s390.cpp b/src/hotspot/cpu/s390/register_s390.cpp index 1746da9f150..853b5642470 100644 --- a/src/hotspot/cpu/s390/register_s390.cpp +++ b/src/hotspot/cpu/s390/register_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 SAP SE. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017 SAP SE. 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 @@ -46,3 +46,13 @@ const char* FloatRegisterImpl::name() const { }; return is_valid() ? names[encoding()] : "fnoreg"; } + +const char* VectorRegisterImpl::name() const { + const char* names[number_of_registers] = { + "Z_V0", "Z_V1", "Z_V2", "Z_V3", "Z_V4", "Z_V5", "Z_V6", "Z_V7", + "Z_V8", "Z_V9", "Z_V10", "Z_V11", "Z_V12", "Z_V13", "Z_V14", "Z_V15", + "Z_V16", "Z_V17", "Z_V18", "Z_V19", "Z_V20", "Z_V21", "Z_V22", "Z_V23", + "Z_V24", "Z_V25", "Z_V26", "Z_V27", "Z_V28", "Z_V29", "Z_V30", "Z_V31" + }; + return is_valid() ? names[encoding()] : "fnoreg"; +} diff --git a/src/hotspot/cpu/s390/register_s390.hpp b/src/hotspot/cpu/s390/register_s390.hpp index 4c61174a613..f8f218e1dd6 100644 --- a/src/hotspot/cpu/s390/register_s390.hpp +++ b/src/hotspot/cpu/s390/register_s390.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 SAP SE. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017 SAP SE. 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 @@ -34,11 +34,6 @@ class VMRegImpl; typedef VMRegImpl* VMReg; -// Use Register as shortcut. -class RegisterImpl; -typedef RegisterImpl* Register; - -// The implementation of integer registers for z/Architecture. // z/Architecture registers, see "LINUX for zSeries ELF ABI Supplement", IBM March 2001 // @@ -57,6 +52,17 @@ typedef RegisterImpl* Register; // f1,f3,f5,f7 General purpose (volatile) // f8-f15 General purpose (nonvolatile) + +//=========================== +//=== Integer Registers === +//=========================== + +// Use Register as shortcut. +class RegisterImpl; +typedef RegisterImpl* Register; + +// The implementation of integer registers for z/Architecture. + inline Register as_Register(int encoding) { return (Register)(long)encoding; } @@ -110,6 +116,11 @@ CONSTANT_REGISTER_DECLARATION(Register, Z_R13, (13)); CONSTANT_REGISTER_DECLARATION(Register, Z_R14, (14)); CONSTANT_REGISTER_DECLARATION(Register, Z_R15, (15)); + +//============================= +//=== Condition Registers === +//============================= + // Use ConditionRegister as shortcut class ConditionRegisterImpl; typedef ConditionRegisterImpl* ConditionRegister; @@ -159,7 +170,7 @@ CONSTANT_REGISTER_DECLARATION(ConditionRegister, Z_CR, (0)); // dangers of defines. // If a particular file has a problem with these defines then it's possible // to turn them off in that file by defining -// DONT_USE_REGISTER_DEFINES. Register_definition_s390.cpp does that +// DONT_USE_REGISTER_DEFINES. Register_definitions_s390.cpp does that // so that it's able to provide real definitions of these registers // for use in debuggers and such. @@ -186,6 +197,11 @@ CONSTANT_REGISTER_DECLARATION(ConditionRegister, Z_CR, (0)); #define Z_CR ((ConditionRegister)(Z_CR_ConditionRegisterEnumValue)) #endif // DONT_USE_REGISTER_DEFINES + +//========================= +//=== Float Registers === +//========================= + // Use FloatRegister as shortcut class FloatRegisterImpl; typedef FloatRegisterImpl* FloatRegister; @@ -263,22 +279,6 @@ CONSTANT_REGISTER_DECLARATION(FloatRegister, Z_F15, (15)); #define Z_F15 ((FloatRegister)( Z_F15_FloatRegisterEnumValue)) #endif // DONT_USE_REGISTER_DEFINES -// Need to know the total number of registers of all sorts for SharedInfo. -// Define a class that exports it. - -class ConcreteRegisterImpl : public AbstractRegisterImpl { - public: - enum { - number_of_registers = - (RegisterImpl::number_of_registers + - FloatRegisterImpl::number_of_registers) - * 2 // register halves - + 1 // condition code register - }; - static const int max_gpr; - static const int max_fpr; -}; - // Single, Double and Quad fp reg classes. These exist to map the ADLC // encoding for a floating point register, to the FloatRegister number // desired by the macroassembler. A FloatRegister is a number between @@ -329,6 +329,161 @@ class QuadFloatRegisterImpl { }; +//========================== +//=== Vector Registers === +//========================== + +// Use VectorRegister as shortcut +class VectorRegisterImpl; +typedef VectorRegisterImpl* VectorRegister; + +// The implementation of vector registers for z/Architecture. + +inline VectorRegister as_VectorRegister(int encoding) { + return (VectorRegister)(long)encoding; +} + +class VectorRegisterImpl: public AbstractRegisterImpl { + public: + enum { + number_of_registers = 32, + number_of_arg_registers = 0 + }; + + // construction + inline friend VectorRegister as_VectorRegister(int encoding); + + inline VMReg as_VMReg(); + + // accessors + int encoding() const { + assert(is_valid(), "invalid register"); return value(); + } + + bool is_valid() const { return 0 <= value() && value() < number_of_registers; } + bool is_volatile() const { return true; } + bool is_nonvolatile() const { return false; } + + // Register fields in z/Architecture instructions are 4 bits wide, restricting the + // addressable register set size to 16. + // The vector register set size is 32, requiring an extension, by one bit, of the + // register encoding. This is accomplished by the introduction of a RXB field in the + // instruction. RXB = Register eXtension Bits. + // The RXB field contains the MSBs (most significant bit) of the vector register numbers + // used for this instruction. Assignment of MSB in RBX is by bit position of the + // register field in the instruction. + // Example: + // The register field starting at bit position 12 in the instruction is assigned RXB bit 0b0100. + int64_t RXB_mask(int pos) { + if (encoding() >= number_of_registers/2) { + switch (pos) { + case 8: return ((int64_t)0b1000) << 8; // actual bit pos: 36 + case 12: return ((int64_t)0b0100) << 8; // actual bit pos: 37 + case 16: return ((int64_t)0b0010) << 8; // actual bit pos: 38 + case 32: return ((int64_t)0b0001) << 8; // actual bit pos: 39 + default: + ShouldNotReachHere(); + } + } + return 0; + } + + const char* name() const; + + VectorRegister successor() const { return as_VectorRegister(encoding() + 1); } +}; + +// The Vector registers of z/Architecture. + +CONSTANT_REGISTER_DECLARATION(VectorRegister, vnoreg, (-1)); + +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V0, (0)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V1, (1)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V2, (2)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V3, (3)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V4, (4)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V5, (5)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V6, (6)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V7, (7)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V8, (8)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V9, (9)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V10, (10)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V11, (11)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V12, (12)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V13, (13)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V14, (14)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V15, (15)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V16, (16)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V17, (17)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V18, (18)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V19, (19)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V20, (20)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V21, (21)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V22, (22)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V23, (23)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V24, (24)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V25, (25)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V26, (26)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V27, (27)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V28, (28)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V29, (29)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V30, (30)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, Z_V31, (31)); + +#ifndef DONT_USE_REGISTER_DEFINES +#define vnoreg ((VectorRegister)(vnoreg_VectorRegisterEnumValue)) +#define Z_V0 ((VectorRegister)( Z_V0_VectorRegisterEnumValue)) +#define Z_V1 ((VectorRegister)( Z_V1_VectorRegisterEnumValue)) +#define Z_V2 ((VectorRegister)( Z_V2_VectorRegisterEnumValue)) +#define Z_V3 ((VectorRegister)( Z_V3_VectorRegisterEnumValue)) +#define Z_V4 ((VectorRegister)( Z_V4_VectorRegisterEnumValue)) +#define Z_V5 ((VectorRegister)( Z_V5_VectorRegisterEnumValue)) +#define Z_V6 ((VectorRegister)( Z_V6_VectorRegisterEnumValue)) +#define Z_V7 ((VectorRegister)( Z_V7_VectorRegisterEnumValue)) +#define Z_V8 ((VectorRegister)( Z_V8_VectorRegisterEnumValue)) +#define Z_V9 ((VectorRegister)( Z_V9_VectorRegisterEnumValue)) +#define Z_V10 ((VectorRegister)( Z_V10_VectorRegisterEnumValue)) +#define Z_V11 ((VectorRegister)( Z_V11_VectorRegisterEnumValue)) +#define Z_V12 ((VectorRegister)( Z_V12_VectorRegisterEnumValue)) +#define Z_V13 ((VectorRegister)( Z_V13_VectorRegisterEnumValue)) +#define Z_V14 ((VectorRegister)( Z_V14_VectorRegisterEnumValue)) +#define Z_V15 ((VectorRegister)( Z_V15_VectorRegisterEnumValue)) +#define Z_V16 ((VectorRegister)( Z_V16_VectorRegisterEnumValue)) +#define Z_V17 ((VectorRegister)( Z_V17_VectorRegisterEnumValue)) +#define Z_V18 ((VectorRegister)( Z_V18_VectorRegisterEnumValue)) +#define Z_V19 ((VectorRegister)( Z_V19_VectorRegisterEnumValue)) +#define Z_V20 ((VectorRegister)( Z_V20_VectorRegisterEnumValue)) +#define Z_V21 ((VectorRegister)( Z_V21_VectorRegisterEnumValue)) +#define Z_V22 ((VectorRegister)( Z_V22_VectorRegisterEnumValue)) +#define Z_V23 ((VectorRegister)( Z_V23_VectorRegisterEnumValue)) +#define Z_V24 ((VectorRegister)( Z_V24_VectorRegisterEnumValue)) +#define Z_V25 ((VectorRegister)( Z_V25_VectorRegisterEnumValue)) +#define Z_V26 ((VectorRegister)( Z_V26_VectorRegisterEnumValue)) +#define Z_V27 ((VectorRegister)( Z_V27_VectorRegisterEnumValue)) +#define Z_V28 ((VectorRegister)( Z_V28_VectorRegisterEnumValue)) +#define Z_V29 ((VectorRegister)( Z_V29_VectorRegisterEnumValue)) +#define Z_V30 ((VectorRegister)( Z_V30_VectorRegisterEnumValue)) +#define Z_V31 ((VectorRegister)( Z_V31_VectorRegisterEnumValue)) +#endif // DONT_USE_REGISTER_DEFINES + + +// Need to know the total number of registers of all sorts for SharedInfo. +// Define a class that exports it. + +class ConcreteRegisterImpl : public AbstractRegisterImpl { + public: + enum { + number_of_registers = + (RegisterImpl::number_of_registers + + FloatRegisterImpl::number_of_registers) + * 2 // register halves + + 1 // condition code register + }; + static const int max_gpr; + static const int max_fpr; +}; + + // Common register declarations used in assembler code. REGISTER_DECLARATION(Register, Z_EXC_OOP, Z_R2); REGISTER_DECLARATION(Register, Z_EXC_PC, Z_R3); diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index b30437e0faf..15902d9f7aa 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -3149,7 +3149,7 @@ operand noArg_iRegI() %{ interface(REG_INTER); %} -// Revenregi and roddRegI constitute and even-odd-pair. +// revenRegI and roddRegI constitute and even-odd-pair. operand revenRegI() %{ constraint(ALLOC_IN_RC(z_rarg3_int_reg)); match(iRegI); @@ -3157,7 +3157,7 @@ operand revenRegI() %{ interface(REG_INTER); %} -// Revenregi and roddRegI constitute and even-odd-pair. +// revenRegI and roddRegI constitute and even-odd-pair. operand roddRegI() %{ constraint(ALLOC_IN_RC(z_rarg4_int_reg)); match(iRegI); @@ -3283,7 +3283,7 @@ operand memoryRegP() %{ interface(REG_INTER); %} -// Revenregp and roddRegP constitute and even-odd-pair. +// revenRegP and roddRegP constitute and even-odd-pair. operand revenRegP() %{ constraint(ALLOC_IN_RC(z_rarg3_ptr_reg)); match(iRegP); @@ -3291,7 +3291,7 @@ operand revenRegP() %{ interface(REG_INTER); %} -// Revenregl and roddRegL constitute and even-odd-pair. +// revenRegP and roddRegP constitute and even-odd-pair. operand roddRegP() %{ constraint(ALLOC_IN_RC(z_rarg4_ptr_reg)); match(iRegP); @@ -3380,7 +3380,7 @@ operand iRegL() %{ interface(REG_INTER); %} -// Revenregl and roddRegL constitute and even-odd-pair. +// revenRegL and roddRegL constitute and even-odd-pair. operand revenRegL() %{ constraint(ALLOC_IN_RC(z_rarg3_long_reg)); match(iRegL); @@ -3388,7 +3388,7 @@ operand revenRegL() %{ interface(REG_INTER); %} -// Revenregl and roddRegL constitute and even-odd-pair. +// revenRegL and roddRegL constitute and even-odd-pair. operand roddRegL() %{ constraint(ALLOC_IN_RC(z_rarg4_long_reg)); match(iRegL); @@ -6443,6 +6443,32 @@ instruct mulL_Reg_mem(iRegL dst, memory src)%{ ins_pipe(pipe_class_dummy); %} +instruct mulHiL_reg_reg(revenRegL Rdst, roddRegL Rsrc1, iRegL Rsrc2, iRegL Rtmp1, flagsReg cr)%{ + match(Set Rdst (MulHiL Rsrc1 Rsrc2)); + effect(TEMP_DEF Rdst, USE_KILL Rsrc1, TEMP Rtmp1, KILL cr); + ins_cost(7*DEFAULT_COST); + // TODO: s390 port size(VARIABLE_SIZE); + format %{ "MulHiL $Rdst, $Rsrc1, $Rsrc2\t # Multiply High Long" %} + ins_encode%{ + Register dst = $Rdst$$Register; + Register src1 = $Rsrc1$$Register; + Register src2 = $Rsrc2$$Register; + Register tmp1 = $Rtmp1$$Register; + Register tmp2 = $Rdst$$Register; + // z/Architecture has only unsigned multiply (64 * 64 -> 128). + // implementing mulhs(a,b) = mulhu(a,b) – (a & (b>>63)) – (b & (a>>63)) + __ z_srag(tmp2, src1, 63); // a>>63 + __ z_srag(tmp1, src2, 63); // b>>63 + __ z_ngr(tmp2, src2); // b & (a>>63) + __ z_ngr(tmp1, src1); // a & (b>>63) + __ z_agr(tmp1, tmp2); // ((a & (b>>63)) + (b & (a>>63))) + __ z_mlgr(dst, src2); // tricky: 128-bit product is written to even/odd pair (dst,src1), + // multiplicand is taken from oddReg (src1), multiplier in src2. + __ z_sgr(dst, tmp1); + %} + ins_pipe(pipe_class_dummy); +%} + // DIV // Integer DIVMOD with Register, both quotient and mod results diff --git a/src/hotspot/cpu/s390/templateTable_s390.cpp b/src/hotspot/cpu/s390/templateTable_s390.cpp index becbb0e48b5..50477e6e556 100644 --- a/src/hotspot/cpu/s390/templateTable_s390.cpp +++ b/src/hotspot/cpu/s390/templateTable_s390.cpp @@ -2382,6 +2382,7 @@ void TemplateTable::load_field_cp_cache_entry(Register obj, if (is_static) { __ mem2reg_opt(obj, Address(cache, index, cp_base_offset + ConstantPoolCacheEntry::f1_offset())); __ mem2reg_opt(obj, Address(obj, Klass::java_mirror_offset())); + __ resolve_oop_handle(obj); } } diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp index 709a9fdf6ed..51383d6db75 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.cpp +++ b/src/hotspot/cpu/s390/vm_version_s390.cpp @@ -224,7 +224,7 @@ void VM_Version::initialize() { } // z/Architecture supports 8-byte compare-exchange operations - // (see Atomic::cmpxchg and StubGenerator::generate_atomic_cmpxchg_ptr) + // (see Atomic::cmpxchg) // and 'atomic long memory ops' (see Unsafe_GetLongVolatile). _supports_cx8 = true; @@ -706,13 +706,13 @@ void VM_Version::determine_features() { Label getCPUFEATURES; // fcode = -1 (cache) Label getCIPHERFEATURES; // fcode = -2 (cipher) Label getMSGDIGESTFEATURES; // fcode = -3 (SHA) - Label checkLongDispFast; - Label noLongDisp; - Label posDisp, negDisp; + Label getVECTORFEATURES; // fcode = -4 (OS support for vector instructions) Label errRTN; a->z_ltgfr(Z_R0, Z_ARG2); // Buf len to r0 and test. - a->z_brl(getFEATURES); // negative -> Get machine features. - a->z_brz(checkLongDispFast); // zero -> Check for high-speed Long Displacement Facility. + a->z_brl(getFEATURES); // negative -> Get machine features not covered by facility list. + a->z_lghi(Z_R1,0); + a->z_brz(errRTN); // zero -> Function code currently not used, indicate "aborted". + a->z_aghi(Z_R0, -1); a->z_stfle(0, Z_ARG1); a->z_lg(Z_R1, 0, Z_ARG1); // Get first DW of facility list. @@ -736,6 +736,8 @@ void VM_Version::determine_features() { a->z_bre(getCIPHERFEATURES); a->z_cghi(Z_R0, -3); // -3: Extract detailed crypto capabilities (msg digest instructions). a->z_bre(getMSGDIGESTFEATURES); + a->z_cghi(Z_R0, -4); // -4: Verify vector instruction availability (OS support). + a->z_bre(getVECTORFEATURES); a->z_xgr(Z_RET, Z_RET); // Not a valid function code. a->z_br(Z_R14); // Return "operation aborted". @@ -766,46 +768,9 @@ void VM_Version::determine_features() { a->z_ecag(Z_RET,Z_R0,0,Z_ARG3); // Extract information as requested by Z_ARG1 contents. a->z_br(Z_R14); - // Check the performance of the Long Displacement Facility, i.e. find out if we are running on z900 or newer. - a->bind(checkLongDispFast); - a->z_llill(Z_R0, 0xffff); // preset #iterations - a->z_larl(Z_R1, posDisp); - a->z_stck(0, Z_ARG1); // Get begin timestamp. - - a->bind(posDisp); // Positive disp loop. - a->z_lg(Z_ARG2, 0, Z_ARG1); - a->z_bctgr(Z_R0, Z_R1); - - a->z_stck(0, Z_ARG1); // Get end timestamp. - a->z_sg(Z_ARG2, 0, Z_R0, Z_ARG1); // Calculate elapsed time. - a->z_lcgr(Z_ARG2, Z_ARG2); - a->z_srlg(Z_ARG2, Z_ARG2, 12); // LSB: now microseconds - a->z_stg(Z_ARG2, 8, Z_ARG1); // Store difference in buffer[1]. - - a->z_llill(Z_R0, 0xffff); // preset #iterations - a->z_larl(Z_R1, negDisp); - a->z_xgr(Z_ARG2, Z_ARG2); // Clear to detect absence of LongDisp facility. - a->z_stck(0, Z_ARG1); // Get begin timestamp. - a->z_la(Z_ARG1, 8, Z_ARG1); - - a->bind(negDisp); // Negative disp loop. - a->z_lg(Z_ARG2, -8, Z_ARG1); - a->z_bctgr(Z_R0, Z_R1); - - a->z_aghi(Z_ARG1, -8); - a->z_stck(0, Z_ARG1); // Get end timestamp. - a->z_ltgr(Z_ARG2, Z_ARG2); // Check for absence of LongDisp facility. - a->z_brz(noLongDisp); - a->z_sg(Z_ARG2, 0, Z_R0, Z_ARG1); // Calc elapsed time. - a->z_lcgr(Z_ARG2, Z_ARG2); - a->z_srlg(Z_ARG2, Z_ARG2, 12); // LSB: now microseconds - a->z_stg(Z_ARG2, 0, Z_ARG1); // store difference in buffer[0] - - a->z_llill(Z_RET,0xffff); - a->z_br(Z_R14); - - a->bind(noLongDisp); - a->z_lghi(Z_RET,-1); + // Use a vector instruction to verify OS support. Will fail with SIGFPE if OS support is missing. + a->bind(getVECTORFEATURES); + a->z_vtm(Z_V0,Z_V0); // non-destructive vector instruction. Will cause SIGFPE if not supported. a->z_br(Z_R14); address code_end = a->pc(); @@ -962,6 +927,19 @@ void VM_Version::determine_features() { _nfeatures = 0; } + if (has_VectorFacility()) { + // Verify that feature can actually be used. OS support required. + call_getFeatures(buffer, -4, 0); + if (printVerbose) { + ttyLocker ttyl; + if (has_VectorFacility()) { + tty->print_cr(" Vector Facility has been verified to be supported by OS"); + } else { + tty->print_cr(" Vector Facility has been disabled - not supported by OS"); + } + } + } + // Extract Crypto Facility details. if (has_Crypto()) { // Get cipher features. diff --git a/src/hotspot/cpu/s390/vm_version_s390.hpp b/src/hotspot/cpu/s390/vm_version_s390.hpp index 7aa66bffc39..0f5d754707b 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.hpp +++ b/src/hotspot/cpu/s390/vm_version_s390.hpp @@ -473,6 +473,8 @@ class VM_Version: public Abstract_VM_Version { static void set_has_CryptoExt5() { _features[0] |= CryptoExtension5Mask; } static void set_has_VectorFacility() { _features[2] |= VectorFacilityMask; } + static void reset_has_VectorFacility() { _features[2] &= ~VectorFacilityMask; } + // Assembler testing. static void allow_all(); static void revert(); diff --git a/src/hotspot/cpu/sparc/assembler_sparc.hpp b/src/hotspot/cpu/sparc/assembler_sparc.hpp index 69822951928..f8f5b11c9a6 100644 --- a/src/hotspot/cpu/sparc/assembler_sparc.hpp +++ b/src/hotspot/cpu/sparc/assembler_sparc.hpp @@ -122,6 +122,7 @@ class Assembler : public AbstractAssembler { fpop1_op3 = 0x34, fpop2_op3 = 0x35, impdep1_op3 = 0x36, + addx_op3 = 0x36, aes3_op3 = 0x36, sha_op3 = 0x36, bmask_op3 = 0x36, @@ -133,6 +134,8 @@ class Assembler : public AbstractAssembler { fzero_op3 = 0x36, fsrc_op3 = 0x36, fnot_op3 = 0x36, + mpmul_op3 = 0x36, + umulx_op3 = 0x36, xmulx_op3 = 0x36, crc32c_op3 = 0x36, impdep2_op3 = 0x37, @@ -195,6 +198,9 @@ class Assembler : public AbstractAssembler { fnegs_opf = 0x05, fnegd_opf = 0x06, + addxc_opf = 0x11, + addxccc_opf = 0x13, + umulxhi_opf = 0x16, alignaddr_opf = 0x18, bmask_opf = 0x19, @@ -240,7 +246,8 @@ class Assembler : public AbstractAssembler { sha256_opf = 0x142, sha512_opf = 0x143, - crc32c_opf = 0x147 + crc32c_opf = 0x147, + mpmul_opf = 0x148 }; enum op5s { @@ -380,7 +387,7 @@ class Assembler : public AbstractAssembler { assert_signed_range(x, nbits + 2); } - static void assert_unsigned_const(int x, int nbits) { + static void assert_unsigned_range(int x, int nbits) { assert(juint(x) < juint(1 << nbits), "unsigned constant out of range"); } @@ -534,6 +541,12 @@ class Assembler : public AbstractAssembler { return x & ((1 << nbits) - 1); } + // unsigned immediate, in low bits, at most nbits long. + static int uimm(int x, int nbits) { + assert_unsigned_range(x, nbits); + return x & ((1 << nbits) - 1); + } + // compute inverse of wdisp16 static intptr_t inv_wdisp16(int x, intptr_t pos) { int lo = x & ((1 << 14) - 1); @@ -631,6 +644,9 @@ class Assembler : public AbstractAssembler { // FMAf instructions supported only on certain processors static void fmaf_only() { assert(VM_Version::has_fmaf(), "This instruction only works on SPARC with FMAf"); } + // MPMUL instruction supported only on certain processors + static void mpmul_only() { assert(VM_Version::has_mpmul(), "This instruction only works on SPARC with MPMUL"); } + // instruction only in VIS1 static void vis1_only() { assert(VM_Version::has_vis1(), "This instruction only works on SPARC with VIS1"); } @@ -772,11 +788,12 @@ class Assembler : public AbstractAssembler { AbstractAssembler::flush(); } - inline void emit_int32(int); // shadows AbstractAssembler::emit_int32 - inline void emit_data(int); - inline void emit_data(int, RelocationHolder const &rspec); - inline void emit_data(int, relocInfo::relocType rtype); - // helper for above functions + inline void emit_int32(int32_t); // shadows AbstractAssembler::emit_int32 + inline void emit_data(int32_t); + inline void emit_data(int32_t, RelocationHolder const&); + inline void emit_data(int32_t, relocInfo::relocType rtype); + + // Helper for the above functions. inline void check_delay(); @@ -929,6 +946,10 @@ class Assembler : public AbstractAssembler { // fmaf instructions. inline void fmadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); + inline void fmsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); + + inline void fnmadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); + inline void fnmsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); // pp 165 @@ -960,6 +981,8 @@ class Assembler : public AbstractAssembler { inline void ldf(FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d, RelocationHolder const &rspec = RelocationHolder()); + inline void ldd(Register s1, Register s2, FloatRegister d); + inline void ldd(Register s1, int simm13a, FloatRegister d); inline void ldfsr(Register s1, Register s2); inline void ldfsr(Register s1, int simm13a); @@ -987,8 +1010,6 @@ class Assembler : public AbstractAssembler { inline void lduw(Register s1, int simm13a, Register d); inline void ldx(Register s1, Register s2, Register d); inline void ldx(Register s1, int simm13a, Register d); - inline void ldd(Register s1, Register s2, Register d); - inline void ldd(Register s1, int simm13a, Register d); // pp 177 @@ -1157,6 +1178,9 @@ class Assembler : public AbstractAssembler { inline void stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2); inline void stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a); + inline void std(FloatRegister d, Register s1, Register s2); + inline void std(FloatRegister d, Register s1, int simm13a); + inline void stfsr(Register s1, Register s2); inline void stfsr(Register s1, int simm13a); inline void stxfsr(Register s1, Register s2); @@ -1177,8 +1201,6 @@ class Assembler : public AbstractAssembler { inline void stw(Register d, Register s1, int simm13a); inline void stx(Register d, Register s1, Register s2); inline void stx(Register d, Register s1, int simm13a); - inline void std(Register d, Register s1, Register s2); - inline void std(Register d, Register s1, int simm13a); // pp 177 @@ -1267,6 +1289,9 @@ class Assembler : public AbstractAssembler { // VIS3 instructions + inline void addxc(Register s1, Register s2, Register d); + inline void addxccc(Register s1, Register s2, Register d); + inline void movstosw(FloatRegister s, Register d); inline void movstouw(FloatRegister s, Register d); inline void movdtox(FloatRegister s, Register d); @@ -1276,6 +1301,7 @@ class Assembler : public AbstractAssembler { inline void xmulx(Register s1, Register s2, Register d); inline void xmulxhi(Register s1, Register s2, Register d); + inline void umulxhi(Register s1, Register s2, Register d); // Crypto SHA instructions @@ -1287,6 +1313,10 @@ class Assembler : public AbstractAssembler { inline void crc32c(FloatRegister s1, FloatRegister s2, FloatRegister d); + // MPMUL instruction + + inline void mpmul(int uimm5); + // Creation Assembler(CodeBuffer* code) : AbstractAssembler(code) { #ifdef VALIDATE_PIPELINE diff --git a/src/hotspot/cpu/sparc/assembler_sparc.inline.hpp b/src/hotspot/cpu/sparc/assembler_sparc.inline.hpp index 070a1f80db3..b9a918e5e0b 100644 --- a/src/hotspot/cpu/sparc/assembler_sparc.inline.hpp +++ b/src/hotspot/cpu/sparc/assembler_sparc.inline.hpp @@ -59,7 +59,7 @@ inline void Assembler::check_delay() { #endif } -inline void Assembler::emit_int32(int x) { +inline void Assembler::emit_int32(int32_t x) { check_delay(); #ifdef VALIDATE_PIPELINE _hazard_state = NoHazard; @@ -67,16 +67,16 @@ inline void Assembler::emit_int32(int x) { AbstractAssembler::emit_int32(x); } -inline void Assembler::emit_data(int x) { +inline void Assembler::emit_data(int32_t x) { emit_int32(x); } -inline void Assembler::emit_data(int x, relocInfo::relocType rtype) { +inline void Assembler::emit_data(int32_t x, relocInfo::relocType rtype) { relocate(rtype); emit_int32(x); } -inline void Assembler::emit_data(int x, RelocationHolder const &rspec) { +inline void Assembler::emit_data(int32_t x, RelocationHolder const &rspec) { relocate(rspec); emit_int32(x); } @@ -359,6 +359,19 @@ inline void Assembler::fmadd(FloatRegisterImpl::Width w, FloatRegister s1, Float fmaf_only(); emit_int32(op(arith_op) | fd(d, w) | op3(stpartialf_op3) | fs1(s1, w) | fs3(s3, w) | op5(w) | fs2(s2, w)); } +inline void Assembler::fmsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { + fmaf_only(); + emit_int32(op(arith_op) | fd(d, w) | op3(stpartialf_op3) | fs1(s1, w) | fs3(s3, w) | op5(0x4 + w) | fs2(s2, w)); +} + +inline void Assembler::fnmadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { + fmaf_only(); + emit_int32(op(arith_op) | fd(d, w) | op3(stpartialf_op3) | fs1(s1, w) | fs3(s3, w) | op5(0xc + w) | fs2(s2, w)); +} +inline void Assembler::fnmsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { + fmaf_only(); + emit_int32(op(arith_op) | fd(d, w) | op3(stpartialf_op3) | fs1(s1, w) | fs3(s3, w) | op5(0x8 + w) | fs2(s2, w)); +} inline void Assembler::flush(Register s1, Register s2) { emit_int32(op(arith_op) | op3(flush_op3) | rs1(s1) | rs2(s2)); @@ -402,6 +415,15 @@ inline void Assembler::ldf(FloatRegisterImpl::Width w, Register s1, int simm13a, emit_data(op(ldst_op) | fd(d, w) | alt_op3(ldf_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec); } +inline void Assembler::ldd(Register s1, Register s2, FloatRegister d) { + assert(d->is_even(), "not even"); + ldf(FloatRegisterImpl::D, s1, s2, d); +} +inline void Assembler::ldd(Register s1, int simm13a, FloatRegister d) { + assert(d->is_even(), "not even"); + ldf(FloatRegisterImpl::D, s1, simm13a, d); +} + inline void Assembler::ldxfsr(Register s1, Register s2) { emit_int32(op(ldst_op) | rd(G1) | op3(ldfsr_op3) | rs1(s1) | rs2(s2)); } @@ -460,16 +482,6 @@ inline void Assembler::ldx(Register s1, Register s2, Register d) { inline void Assembler::ldx(Register s1, int simm13a, Register d) { emit_data(op(ldst_op) | rd(d) | op3(ldx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } -inline void Assembler::ldd(Register s1, Register s2, Register d) { - v9_dep(); - assert(d->is_even(), "not even"); - emit_int32(op(ldst_op) | rd(d) | op3(ldd_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::ldd(Register s1, int simm13a, Register d) { - v9_dep(); - assert(d->is_even(), "not even"); - emit_data(op(ldst_op) | rd(d) | op3(ldd_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} inline void Assembler::ldsba(Register s1, Register s2, int ia, Register d) { emit_int32(op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); @@ -806,6 +818,15 @@ inline void Assembler::stf(FloatRegisterImpl::Width w, FloatRegister d, Register emit_data(op(ldst_op) | fd(d, w) | alt_op3(stf_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::std(FloatRegister d, Register s1, Register s2) { + assert(d->is_even(), "not even"); + stf(FloatRegisterImpl::D, d, s1, s2); +} +inline void Assembler::std(FloatRegister d, Register s1, int simm13a) { + assert(d->is_even(), "not even"); + stf(FloatRegisterImpl::D, d, s1, simm13a); +} + inline void Assembler::stxfsr(Register s1, Register s2) { emit_int32(op(ldst_op) | rd(G1) | op3(stfsr_op3) | rs1(s1) | rs2(s2)); } @@ -848,16 +869,6 @@ inline void Assembler::stx(Register d, Register s1, Register s2) { inline void Assembler::stx(Register d, Register s1, int simm13a) { emit_data(op(ldst_op) | rd(d) | op3(stx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } -inline void Assembler::std(Register d, Register s1, Register s2) { - v9_dep(); - assert(d->is_even(), "not even"); - emit_int32(op(ldst_op) | rd(d) | op3(std_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::std(Register d, Register s1, int simm13a) { - v9_dep(); - assert(d->is_even(), "not even"); - emit_data(op(ldst_op) | rd(d) | op3(std_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} inline void Assembler::stba(Register d, Register s1, Register s2, int ia) { emit_int32(op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); @@ -1043,6 +1054,15 @@ inline void Assembler::bshuffle(FloatRegister s1, FloatRegister s2, FloatRegiste // VIS3 instructions +inline void Assembler::addxc(Register s1, Register s2, Register d) { + vis3_only(); + emit_int32(op(arith_op) | rd(d) | op3(addx_op3) | rs1(s1) | opf(addxc_opf) | rs2(s2)); +} +inline void Assembler::addxccc(Register s1, Register s2, Register d) { + vis3_only(); + emit_int32(op(arith_op) | rd(d) | op3(addx_op3) | rs1(s1) | opf(addxccc_opf) | rs2(s2)); +} + inline void Assembler::movstosw(FloatRegister s, Register d) { vis3_only(); emit_int32(op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstosw_opf) | fs2(s, FloatRegisterImpl::S)); @@ -1073,6 +1093,10 @@ inline void Assembler::xmulxhi(Register s1, Register s2, Register d) { vis3_only(); emit_int32(op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulxhi_opf) | rs2(s2)); } +inline void Assembler::umulxhi(Register s1, Register s2, Register d) { + vis3_only(); + emit_int32(op(arith_op) | rd(d) | op3(umulx_op3) | rs1(s1) | opf(umulxhi_opf) | rs2(s2)); +} // Crypto SHA instructions @@ -1096,4 +1120,11 @@ inline void Assembler::crc32c(FloatRegister s1, FloatRegister s2, FloatRegister emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(crc32c_op3) | fs1(s1, FloatRegisterImpl::D) | opf(crc32c_opf) | fs2(s2, FloatRegisterImpl::D)); } +// MPMUL instruction + +inline void Assembler::mpmul(int uimm5) { + mpmul_only(); + emit_int32(op(arith_op) | rd(0) | op3(mpmul_op3) | rs1(0) | opf(mpmul_opf) | uimm(uimm5, 5)); +} + #endif // CPU_SPARC_VM_ASSEMBLER_SPARC_INLINE_HPP diff --git a/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp b/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp index 5269c9fd8be..937252fe752 100644 --- a/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp +++ b/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp @@ -2763,13 +2763,9 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { } Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias); - Bytecodes::Code bc = method->java_code_at_bci(bci); - const bool callee_is_static = callee->is_loaded() && callee->is_static(); // Perform additional virtual call profiling for invokevirtual and // invokeinterface bytecodes - if ((bc == Bytecodes::_invokevirtual || bc == Bytecodes::_invokeinterface) && - !callee_is_static && // required for optimized MH invokes - C1ProfileVirtualCalls) { + if (op->should_profile_receiver_type()) { assert(op->recv()->is_single_cpu(), "recv must be allocated"); Register recv = op->recv()->as_register(); assert_different_registers(mdo, tmp1, recv); diff --git a/src/hotspot/cpu/sparc/frame_sparc.cpp b/src/hotspot/cpu/sparc/frame_sparc.cpp index 4fa7e6a973b..3985a875c34 100644 --- a/src/hotspot/cpu/sparc/frame_sparc.cpp +++ b/src/hotspot/cpu/sparc/frame_sparc.cpp @@ -119,8 +119,8 @@ address RegisterMap::pd_location(VMReg regname) const { reg = regname->as_Register(); } if (reg->is_out()) { - assert(_younger_window != NULL, "Younger window should be available"); - return second_word + (address)&_younger_window[reg->after_save()->sp_offset_in_saved_window()]; + return _younger_window == NULL ? NULL : + second_word + (address)&_younger_window[reg->after_save()->sp_offset_in_saved_window()]; } if (reg->is_local() || reg->is_in()) { assert(_window != NULL, "Window should be available"); diff --git a/src/hotspot/cpu/sparc/globalDefinitions_sparc.hpp b/src/hotspot/cpu/sparc/globalDefinitions_sparc.hpp index 465a6a014e3..cb4bb137ceb 100644 --- a/src/hotspot/cpu/sparc/globalDefinitions_sparc.hpp +++ b/src/hotspot/cpu/sparc/globalDefinitions_sparc.hpp @@ -43,7 +43,7 @@ const bool CCallingConventionRequiresIntsAsLongs = true; #elif defined(COMPILER1) // pure C1, 32-bit, small machine #define DEFAULT_CACHE_LINE_SIZE 16 -#elif defined(COMPILER2) || defined(SHARK) +#elif defined(COMPILER2) // pure C2, 64-bit, large machine #define DEFAULT_CACHE_LINE_SIZE 128 #endif diff --git a/src/hotspot/cpu/sparc/globals_sparc.hpp b/src/hotspot/cpu/sparc/globals_sparc.hpp index 89361fcddbd..a232649f957 100644 --- a/src/hotspot/cpu/sparc/globals_sparc.hpp +++ b/src/hotspot/cpu/sparc/globals_sparc.hpp @@ -97,12 +97,15 @@ define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong); writeable) \ \ product(intx, UseVIS, 99, \ - "Highest supported VIS instructions set on Sparc") \ + "Highest supported VIS instructions set on SPARC") \ range(0, 99) \ \ product(bool, UseCBCond, false, \ "Use compare and branch instruction on SPARC") \ \ + product(bool, UseMPMUL, false, \ + "Use multi-precision multiply instruction (mpmul) on SPARC") \ + \ product(bool, UseBlockZeroing, false, \ "Use special cpu instructions for block zeroing") \ \ diff --git a/src/hotspot/cpu/sparc/jniTypes_sparc.hpp b/src/hotspot/cpu/sparc/jniTypes_sparc.hpp index 50b51fff2c3..bbdb064a9f1 100644 --- a/src/hotspot/cpu/sparc/jniTypes_sparc.hpp +++ b/src/hotspot/cpu/sparc/jniTypes_sparc.hpp @@ -25,9 +25,9 @@ #ifndef CPU_SPARC_VM_JNITYPES_SPARC_HPP #define CPU_SPARC_VM_JNITYPES_SPARC_HPP +#include "jni.h" #include "memory/allocation.hpp" #include "oops/oop.hpp" -#include "prims/jni.h" // This file holds platform-dependent routines used to write primitive jni // types to the array of arguments passed into JavaCalls::call diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp index b667f1b1103..70a65b07298 100644 --- a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp +++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp @@ -1574,29 +1574,39 @@ void MacroAssembler::br_null_short(Register s1, Predict p, Label& L) { assert_not_delayed(); if (use_cbcond(L)) { Assembler::cbcond(zero, ptr_cc, s1, 0, L); - return; + } else { + br_null(s1, false, p, L); + delayed()->nop(); } - br_null(s1, false, p, L); - delayed()->nop(); } void MacroAssembler::br_notnull_short(Register s1, Predict p, Label& L) { assert_not_delayed(); if (use_cbcond(L)) { Assembler::cbcond(notZero, ptr_cc, s1, 0, L); - return; + } else { + br_notnull(s1, false, p, L); + delayed()->nop(); } - br_notnull(s1, false, p, L); - delayed()->nop(); } // Unconditional short branch void MacroAssembler::ba_short(Label& L) { + assert_not_delayed(); if (use_cbcond(L)) { Assembler::cbcond(equal, icc, G0, G0, L); - return; + } else { + br(always, false, pt, L); + delayed()->nop(); } - br(always, false, pt, L); +} + +// Branch if 'icc' says zero or not (i.e. icc.z == 1|0). + +void MacroAssembler::br_icc_zero(bool iszero, Predict p, Label &L) { + assert_not_delayed(); + Condition cf = (iszero ? Assembler::zero : Assembler::notZero); + br(cf, false, p, L); delayed()->nop(); } @@ -3565,20 +3575,6 @@ static void generate_satb_log_enqueue(bool with_frame) { #undef __ } -static inline void generate_satb_log_enqueue_if_necessary(bool with_frame) { - if (with_frame) { - if (satb_log_enqueue_with_frame == 0) { - generate_satb_log_enqueue(with_frame); - assert(satb_log_enqueue_with_frame != 0, "postcondition."); - } - } else { - if (satb_log_enqueue_frameless == 0) { - generate_satb_log_enqueue(with_frame); - assert(satb_log_enqueue_frameless != 0, "postcondition."); - } - } -} - void MacroAssembler::g1_write_barrier_pre(Register obj, Register index, int offset, @@ -3648,13 +3644,9 @@ void MacroAssembler::g1_write_barrier_pre(Register obj, "Or we need to think harder."); if (pre_val->is_global() && !preserve_o_regs) { - generate_satb_log_enqueue_if_necessary(true); // with frame - call(satb_log_enqueue_with_frame); delayed()->mov(pre_val, O0); } else { - generate_satb_log_enqueue_if_necessary(false); // frameless - save_frame(0); call(satb_log_enqueue_frameless); delayed()->mov(pre_val->after_save(), O0); @@ -3758,15 +3750,6 @@ static void generate_dirty_card_log_enqueue(jbyte* byte_map_base) { } -static inline void -generate_dirty_card_log_enqueue_if_necessary(jbyte* byte_map_base) { - if (dirty_card_log_enqueue == 0) { - generate_dirty_card_log_enqueue(byte_map_base); - assert(dirty_card_log_enqueue != 0, "postcondition."); - } -} - - void MacroAssembler::g1_write_barrier_post(Register store_addr, Register new_val, Register tmp) { Label filtered; @@ -3796,7 +3779,6 @@ void MacroAssembler::g1_write_barrier_post(Register store_addr, Register new_val } else { post_filter_masm->nop(); } - generate_dirty_card_log_enqueue_if_necessary(bs->byte_map_base); save_frame(0); call(dirty_card_log_enqueue); if (use_scr) { @@ -3809,6 +3791,28 @@ void MacroAssembler::g1_write_barrier_post(Register store_addr, Register new_val bind(filtered); } +// Called from init_globals() after universe_init() and before interpreter_init() +void g1_barrier_stubs_init() { + CollectedHeap* heap = Universe::heap(); + if (heap->kind() == CollectedHeap::G1CollectedHeap) { + // Only needed for G1 + if (dirty_card_log_enqueue == 0) { + G1SATBCardTableLoggingModRefBS* bs = + barrier_set_cast(heap->barrier_set()); + generate_dirty_card_log_enqueue(bs->byte_map_base); + assert(dirty_card_log_enqueue != 0, "postcondition."); + } + if (satb_log_enqueue_with_frame == 0) { + generate_satb_log_enqueue(true); + assert(satb_log_enqueue_with_frame != 0, "postcondition."); + } + if (satb_log_enqueue_frameless == 0) { + generate_satb_log_enqueue(false); + assert(satb_log_enqueue_frameless != 0, "postcondition."); + } + } +} + #endif // INCLUDE_ALL_GCS /////////////////////////////////////////////////////////////////////////////////// @@ -3834,6 +3838,7 @@ void MacroAssembler::load_mirror(Register mirror, Register method) { ld_ptr(mirror, in_bytes(ConstMethod::constants_offset()), mirror); ld_ptr(mirror, ConstantPool::pool_holder_offset_in_bytes(), mirror); ld_ptr(mirror, mirror_offset, mirror); + resolve_oop_handle(mirror); } void MacroAssembler::load_klass(Register src_oop, Register klass) { diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp index 4f24d0354ee..db1ebf1ead8 100644 --- a/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp +++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp @@ -606,7 +606,7 @@ class MacroAssembler : public Assembler { // offset. No explicit code generation is needed if the offset is within a certain // range (0 <= offset <= page_size). // - // %%%%%% Currently not done for SPARC + // FIXME: Currently not done for SPARC void null_check(Register reg, int offset = -1); static bool needs_explicit_null_check(intptr_t offset); @@ -648,6 +648,9 @@ class MacroAssembler : public Assembler { // unconditional short branch void ba_short(Label& L); + // Branch on icc.z (true or not). + void br_icc_zero(bool iszero, Predict p, Label &L); + inline void bp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt = relocInfo::none ); inline void bp( Condition c, bool a, CC cc, Predict p, Label& L ); @@ -663,19 +666,19 @@ class MacroAssembler : public Assembler { inline void fbp( Condition c, bool a, CC cc, Predict p, Label& L ); // Sparc shorthands(pp 85, V8 manual, pp 289 V9 manual) - inline void cmp( Register s1, Register s2 ); - inline void cmp( Register s1, int simm13a ); + inline void cmp( Register s1, Register s2 ); + inline void cmp( Register s1, int simm13a ); inline void jmp( Register s1, Register s2 ); inline void jmp( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() ); // Check if the call target is out of wdisp30 range (relative to the code cache) static inline bool is_far_target(address d); - inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type ); - inline void call( address d, RelocationHolder const& rspec); + inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type ); + inline void call( address d, RelocationHolder const& rspec); - inline void call( Label& L, relocInfo::relocType rt = relocInfo::runtime_call_type ); - inline void call( Label& L, RelocationHolder const& rspec); + inline void call( Label& L, relocInfo::relocType rt = relocInfo::runtime_call_type ); + inline void call( Label& L, RelocationHolder const& rspec); inline void callr( Register s1, Register s2 ); inline void callr( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() ); diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.inline.hpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.inline.hpp index 679bbd30c29..16871d98629 100644 --- a/src/hotspot/cpu/sparc/macroAssembler_sparc.inline.hpp +++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.inline.hpp @@ -185,7 +185,7 @@ inline void MacroAssembler::br( Condition c, bool a, Predict p, address d, reloc } inline void MacroAssembler::br( Condition c, bool a, Predict p, Label& L ) { - // See note[+] on 'avoid_pipeline_stalls()', in "assembler_sparc.inline.hpp". + // See note[+] on 'avoid_pipeline_stall()', in "assembler_sparc.inline.hpp". avoid_pipeline_stall(); br(c, a, p, target(L)); } diff --git a/src/hotspot/cpu/sparc/register_sparc.hpp b/src/hotspot/cpu/sparc/register_sparc.hpp index 22cb0283825..5682b622d9c 100644 --- a/src/hotspot/cpu/sparc/register_sparc.hpp +++ b/src/hotspot/cpu/sparc/register_sparc.hpp @@ -236,7 +236,7 @@ class FloatRegisterImpl: public AbstractRegisterImpl { inline VMReg as_VMReg( ); // accessors - int encoding() const { assert(is_valid(), "invalid register"); return value(); } + int encoding() const { assert(is_valid(), "invalid register"); return value(); } public: int encoding(Width w) const { @@ -258,10 +258,12 @@ class FloatRegisterImpl: public AbstractRegisterImpl { return -1; } - bool is_valid() const { return 0 <= value() && value() < number_of_registers; } + bool is_valid() const { return 0 <= value() && value() < number_of_registers; } + bool is_even() const { return (encoding() & 1) == 0; } + const char* name() const; - FloatRegister successor() const { return as_FloatRegister(encoding() + 1); } + FloatRegister successor() const { return as_FloatRegister(encoding() + 1); } }; diff --git a/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp b/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp index 4f217e33ac6..357be521a6b 100644 --- a/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp +++ b/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp @@ -41,10 +41,6 @@ #ifdef COMPILER2 #include "opto/runtime.hpp" #endif -#ifdef SHARK -#include "compiler/compileBroker.hpp" -#include "shark/sharkCompiler.hpp" -#endif #if INCLUDE_JVMCI #include "jvmci/jvmciJavaClasses.hpp" #endif diff --git a/src/hotspot/cpu/sparc/sparc.ad b/src/hotspot/cpu/sparc/sparc.ad index 07f62bac5aa..c582cd5a6a8 100644 --- a/src/hotspot/cpu/sparc/sparc.ad +++ b/src/hotspot/cpu/sparc/sparc.ad @@ -2628,7 +2628,6 @@ enc_class fsqrtd (dflt_reg dst, dflt_reg src) %{ %} - enc_class fmadds (sflt_reg dst, sflt_reg a, sflt_reg b, sflt_reg c) %{ MacroAssembler _masm(&cbuf); @@ -2651,7 +2650,71 @@ enc_class fmaddd (dflt_reg dst, dflt_reg a, dflt_reg b, dflt_reg c) %{ __ fmadd(FloatRegisterImpl::D, Fra, Frb, Frc, Frd); %} +enc_class fmsubs (sflt_reg dst, sflt_reg a, sflt_reg b, sflt_reg c) %{ + MacroAssembler _masm(&cbuf); + FloatRegister Frd = reg_to_SingleFloatRegister_object($dst$$reg); + FloatRegister Fra = reg_to_SingleFloatRegister_object($a$$reg); + FloatRegister Frb = reg_to_SingleFloatRegister_object($b$$reg); + FloatRegister Frc = reg_to_SingleFloatRegister_object($c$$reg); + + __ fmsub(FloatRegisterImpl::S, Fra, Frb, Frc, Frd); +%} + +enc_class fmsubd (dflt_reg dst, dflt_reg a, dflt_reg b, dflt_reg c) %{ + MacroAssembler _masm(&cbuf); + + FloatRegister Frd = reg_to_DoubleFloatRegister_object($dst$$reg); + FloatRegister Fra = reg_to_DoubleFloatRegister_object($a$$reg); + FloatRegister Frb = reg_to_DoubleFloatRegister_object($b$$reg); + FloatRegister Frc = reg_to_DoubleFloatRegister_object($c$$reg); + + __ fmsub(FloatRegisterImpl::D, Fra, Frb, Frc, Frd); +%} + +enc_class fnmadds (sflt_reg dst, sflt_reg a, sflt_reg b, sflt_reg c) %{ + MacroAssembler _masm(&cbuf); + + FloatRegister Frd = reg_to_SingleFloatRegister_object($dst$$reg); + FloatRegister Fra = reg_to_SingleFloatRegister_object($a$$reg); + FloatRegister Frb = reg_to_SingleFloatRegister_object($b$$reg); + FloatRegister Frc = reg_to_SingleFloatRegister_object($c$$reg); + + __ fnmadd(FloatRegisterImpl::S, Fra, Frb, Frc, Frd); +%} + +enc_class fnmaddd (dflt_reg dst, dflt_reg a, dflt_reg b, dflt_reg c) %{ + MacroAssembler _masm(&cbuf); + + FloatRegister Frd = reg_to_DoubleFloatRegister_object($dst$$reg); + FloatRegister Fra = reg_to_DoubleFloatRegister_object($a$$reg); + FloatRegister Frb = reg_to_DoubleFloatRegister_object($b$$reg); + FloatRegister Frc = reg_to_DoubleFloatRegister_object($c$$reg); + + __ fnmadd(FloatRegisterImpl::D, Fra, Frb, Frc, Frd); +%} + +enc_class fnmsubs (sflt_reg dst, sflt_reg a, sflt_reg b, sflt_reg c) %{ + MacroAssembler _masm(&cbuf); + + FloatRegister Frd = reg_to_SingleFloatRegister_object($dst$$reg); + FloatRegister Fra = reg_to_SingleFloatRegister_object($a$$reg); + FloatRegister Frb = reg_to_SingleFloatRegister_object($b$$reg); + FloatRegister Frc = reg_to_SingleFloatRegister_object($c$$reg); + + __ fnmsub(FloatRegisterImpl::S, Fra, Frb, Frc, Frd); +%} + +enc_class fnmsubd (dflt_reg dst, dflt_reg a, dflt_reg b, dflt_reg c) %{ + MacroAssembler _masm(&cbuf); + + FloatRegister Frd = reg_to_DoubleFloatRegister_object($dst$$reg); + FloatRegister Fra = reg_to_DoubleFloatRegister_object($a$$reg); + FloatRegister Frb = reg_to_DoubleFloatRegister_object($b$$reg); + FloatRegister Frc = reg_to_DoubleFloatRegister_object($c$$reg); + + __ fnmsub(FloatRegisterImpl::D, Fra, Frb, Frc, Frd); +%} enc_class fmovs (dflt_reg dst, dflt_reg src) %{ @@ -7597,7 +7660,7 @@ instruct sqrtD_reg_reg(regD dst, regD src) %{ ins_pipe(fdivD_reg_reg); %} -// Single precision fused floating-point multiply-add (d = a * b + c). +// Single/Double precision fused floating-point multiply-add (d = a * b + c). instruct fmaF_regx4(regF dst, regF a, regF b, regF c) %{ predicate(UseFMA); match(Set dst (FmaF c (Binary a b))); @@ -7606,7 +7669,6 @@ instruct fmaF_regx4(regF dst, regF a, regF b, regF c) %{ ins_pipe(fmaF_regx4); %} -// Double precision fused floating-point multiply-add (d = a * b + c). instruct fmaD_regx4(regD dst, regD a, regD b, regD c) %{ predicate(UseFMA); match(Set dst (FmaD c (Binary a b))); @@ -7615,6 +7677,66 @@ instruct fmaD_regx4(regD dst, regD a, regD b, regD c) %{ ins_pipe(fmaD_regx4); %} +// Additional patterns matching complement versions that we can map directly to +// variants of the fused multiply-add instructions. + +// Single/Double precision fused floating-point multiply-sub (d = a * b - c) +instruct fmsubF_regx4(regF dst, regF a, regF b, regF c) %{ + predicate(UseFMA); + match(Set dst (FmaF (NegF c) (Binary a b))); + format %{ "fmsubs $a,$b,$c,$dst\t# $dst = $a * $b - $c" %} + ins_encode(fmsubs(dst, a, b, c)); + ins_pipe(fmaF_regx4); +%} + +instruct fmsubD_regx4(regD dst, regD a, regD b, regD c) %{ + predicate(UseFMA); + match(Set dst (FmaD (NegD c) (Binary a b))); + format %{ "fmsubd $a,$b,$c,$dst\t# $dst = $a * $b - $c" %} + ins_encode(fmsubd(dst, a, b, c)); + ins_pipe(fmaD_regx4); +%} + +// Single/Double precision fused floating-point neg. multiply-add, +// d = -1 * a * b - c = -(a * b + c) +instruct fnmaddF_regx4(regF dst, regF a, regF b, regF c) %{ + predicate(UseFMA); + match(Set dst (FmaF (NegF c) (Binary (NegF a) b))); + match(Set dst (FmaF (NegF c) (Binary a (NegF b)))); + format %{ "fnmadds $a,$b,$c,$dst\t# $dst = -($a * $b + $c)" %} + ins_encode(fnmadds(dst, a, b, c)); + ins_pipe(fmaF_regx4); +%} + +instruct fnmaddD_regx4(regD dst, regD a, regD b, regD c) %{ + predicate(UseFMA); + match(Set dst (FmaD (NegD c) (Binary (NegD a) b))); + match(Set dst (FmaD (NegD c) (Binary a (NegD b)))); + format %{ "fnmaddd $a,$b,$c,$dst\t# $dst = -($a * $b + $c)" %} + ins_encode(fnmaddd(dst, a, b, c)); + ins_pipe(fmaD_regx4); +%} + +// Single/Double precision fused floating-point neg. multiply-sub, +// d = -1 * a * b + c = -(a * b - c) +instruct fnmsubF_regx4(regF dst, regF a, regF b, regF c) %{ + predicate(UseFMA); + match(Set dst (FmaF c (Binary (NegF a) b))); + match(Set dst (FmaF c (Binary a (NegF b)))); + format %{ "fnmsubs $a,$b,$c,$dst\t# $dst = -($a * $b - $c)" %} + ins_encode(fnmsubs(dst, a, b, c)); + ins_pipe(fmaF_regx4); +%} + +instruct fnmsubD_regx4(regD dst, regD a, regD b, regD c) %{ + predicate(UseFMA); + match(Set dst (FmaD c (Binary (NegD a) b))); + match(Set dst (FmaD c (Binary a (NegD b)))); + format %{ "fnmsubd $a,$b,$c,$dst\t# $dst = -($a * $b - $c)" %} + ins_encode(fnmsubd(dst, a, b, c)); + ins_pipe(fmaD_regx4); +%} + //----------Logical Instructions----------------------------------------------- // And Instructions // Register And diff --git a/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp b/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp index 9c4713e936d..351555dbe51 100644 --- a/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp +++ b/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp @@ -58,7 +58,6 @@ // Note: The register L7 is used as L7_thread_cache, and may not be used // any other way within this module. - static const Register& Lstub_temp = L2; // ------------------------------------------------------------------------------------------------------------------------- @@ -4943,7 +4942,7 @@ class StubGenerator: public StubCodeGenerator { return start; } -/** + /** * Arguments: * * Inputs: @@ -4975,6 +4974,773 @@ class StubGenerator: public StubCodeGenerator { return start; } + /** + * Arguments: + * + * Inputs: + * I0 - int* x-addr + * I1 - int x-len + * I2 - int* y-addr + * I3 - int y-len + * I4 - int* z-addr (output vector) + * I5 - int z-len + */ + address generate_multiplyToLen() { + assert(UseMultiplyToLenIntrinsic, "need VIS3 instructions"); + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "multiplyToLen"); + address start = __ pc(); + + __ save_frame(0); + + const Register xptr = I0; // input address + const Register xlen = I1; // ...and length in 32b-words + const Register yptr = I2; // + const Register ylen = I3; // + const Register zptr = I4; // output address + const Register zlen = I5; // ...and length in 32b-words + + /* The minimal "limb" representation suggest that odd length vectors are as + * likely as even length dittos. This in turn suggests that we need to cope + * with odd/even length arrays and data not aligned properly for 64-bit read + * and write operations. We thus use a number of different kernels: + * + * if (is_even(x.len) && is_even(y.len)) + * if (is_align64(x) && is_align64(y) && is_align64(z)) + * if (x.len == y.len && 16 <= x.len && x.len <= 64) + * memv_mult_mpmul(...) + * else + * memv_mult_64x64(...) + * else + * memv_mult_64x64u(...) + * else + * memv_mult_32x32(...) + * + * Here we assume VIS3 support (for 'umulxhi', 'addxc' and 'addxccc'). + * In case CBCOND instructions are supported, we will use 'cxbX'. If the + * MPMUL instruction is supported, we will generate a kernel using 'mpmul' + * (for vectors with proper characteristics). + */ + const Register tmp0 = L0; + const Register tmp1 = L1; + + Label L_mult_32x32; + Label L_mult_64x64u; + Label L_mult_64x64; + Label L_exit; + + if_both_even(xlen, ylen, tmp0, false, L_mult_32x32); + if_all3_aligned(xptr, yptr, zptr, tmp1, 64, false, L_mult_64x64u); + + if (UseMPMUL) { + if_eq(xlen, ylen, false, L_mult_64x64); + if_in_rng(xlen, 16, 64, tmp0, tmp1, false, L_mult_64x64); + + // 1. Multiply naturally aligned 64b-datums using a generic 'mpmul' kernel, + // operating on equal length vectors of size [16..64]. + gen_mult_mpmul(xlen, xptr, yptr, zptr, L_exit); + } + + // 2. Multiply naturally aligned 64-bit datums (64x64). + __ bind(L_mult_64x64); + gen_mult_64x64(xptr, xlen, yptr, ylen, zptr, zlen, L_exit); + + // 3. Multiply unaligned 64-bit datums (64x64). + __ bind(L_mult_64x64u); + gen_mult_64x64_unaligned(xptr, xlen, yptr, ylen, zptr, zlen, L_exit); + + // 4. Multiply naturally aligned 32-bit datums (32x32). + __ bind(L_mult_32x32); + gen_mult_32x32(xptr, xlen, yptr, ylen, zptr, zlen, L_exit); + + __ bind(L_exit); + __ ret(); + __ delayed()->restore(); + + return start; + } + + // Additional help functions used by multiplyToLen generation. + + void if_both_even(Register r1, Register r2, Register tmp, bool iseven, Label &L) + { + __ or3(r1, r2, tmp); + __ andcc(tmp, 0x1, tmp); + __ br_icc_zero(iseven, Assembler::pn, L); + } + + void if_all3_aligned(Register r1, Register r2, Register r3, + Register tmp, uint align, bool isalign, Label &L) + { + __ or3(r1, r2, tmp); + __ or3(r3, tmp, tmp); + __ andcc(tmp, (align - 1), tmp); + __ br_icc_zero(isalign, Assembler::pn, L); + } + + void if_eq(Register x, Register y, bool iseq, Label &L) + { + Assembler::Condition cf = (iseq ? Assembler::equal : Assembler::notEqual); + __ cmp_and_br_short(x, y, cf, Assembler::pt, L); + } + + void if_in_rng(Register x, int lb, int ub, Register t1, Register t2, bool inrng, Label &L) + { + assert(Assembler::is_simm13(lb), "Small ints only!"); + assert(Assembler::is_simm13(ub), "Small ints only!"); + // Compute (x - lb) * (ub - x) >= 0 + // NOTE: With the local use of this routine, we rely on small integers to + // guarantee that we do not overflow in the multiplication. + __ add(G0, ub, t2); + __ sub(x, lb, t1); + __ sub(t2, x, t2); + __ mulx(t1, t2, t1); + Assembler::Condition cf = (inrng ? Assembler::greaterEqual : Assembler::less); + __ cmp_and_br_short(t1, G0, cf, Assembler::pt, L); + } + + void ldd_entry(Register base, Register offs, FloatRegister dest) + { + __ ldd(base, offs, dest); + __ inc(offs, 8); + } + + void ldx_entry(Register base, Register offs, Register dest) + { + __ ldx(base, offs, dest); + __ inc(offs, 8); + } + + void mpmul_entry(int m, Label &next) + { + __ mpmul(m); + __ cbcond(Assembler::equal, Assembler::icc, G0, G0, next); + } + + void stx_entry(Label &L, Register r1, Register r2, Register base, Register offs) + { + __ bind(L); + __ stx(r1, base, offs); + __ inc(offs, 8); + __ stx(r2, base, offs); + __ inc(offs, 8); + } + + void offs_entry(Label &Lbl0, Label &Lbl1) + { + assert(Lbl0.is_bound(), "must be"); + assert(Lbl1.is_bound(), "must be"); + + int offset = Lbl0.loc_pos() - Lbl1.loc_pos(); + + __ emit_data(offset); + } + + /* Generate the actual multiplication kernels for BigInteger vectors: + * + * 1. gen_mult_mpmul(...) + * + * 2. gen_mult_64x64(...) + * + * 3. gen_mult_64x64_unaligned(...) + * + * 4. gen_mult_32x32(...) + */ + void gen_mult_mpmul(Register len, Register xptr, Register yptr, Register zptr, + Label &L_exit) + { + const Register zero = G0; + const Register gxp = G1; // Need to use global registers across RWs. + const Register gyp = G2; + const Register gzp = G3; + const Register offs = G4; + const Register disp = G5; + + __ mov(xptr, gxp); + __ mov(yptr, gyp); + __ mov(zptr, gzp); + + /* Compute jump vector entry: + * + * 1. mpmul input size (0..31) x 64b + * 2. vector input size in 32b limbs (even number) + * 3. branch entries in reverse order (31..0), using two + * instructions per entry (2 * 4 bytes). + * + * displacement = byte_offset(bra_offset(len)) + * = byte_offset((64 - len)/2) + * = 8 * (64 - len)/2 + * = 4 * (64 - len) + */ + Register temp = I5; // Alright to use input regs. in first batch. + + __ sub(zero, len, temp); + __ add(temp, 64, temp); + __ sllx(temp, 2, disp); // disp := (64 - len) << 2 + + // Dispatch relative current PC, into instruction table below. + __ rdpc(temp); + __ add(temp, 16, temp); + __ jmp(temp, disp); + __ delayed()->clr(offs); + + ldd_entry(gxp, offs, F22); + ldd_entry(gxp, offs, F20); + ldd_entry(gxp, offs, F18); + ldd_entry(gxp, offs, F16); + ldd_entry(gxp, offs, F14); + ldd_entry(gxp, offs, F12); + ldd_entry(gxp, offs, F10); + ldd_entry(gxp, offs, F8); + ldd_entry(gxp, offs, F6); + ldd_entry(gxp, offs, F4); + ldx_entry(gxp, offs, I5); + ldx_entry(gxp, offs, I4); + ldx_entry(gxp, offs, I3); + ldx_entry(gxp, offs, I2); + ldx_entry(gxp, offs, I1); + ldx_entry(gxp, offs, I0); + ldx_entry(gxp, offs, L7); + ldx_entry(gxp, offs, L6); + ldx_entry(gxp, offs, L5); + ldx_entry(gxp, offs, L4); + ldx_entry(gxp, offs, L3); + ldx_entry(gxp, offs, L2); + ldx_entry(gxp, offs, L1); + ldx_entry(gxp, offs, L0); + ldd_entry(gxp, offs, F2); + ldd_entry(gxp, offs, F0); + ldx_entry(gxp, offs, O5); + ldx_entry(gxp, offs, O4); + ldx_entry(gxp, offs, O3); + ldx_entry(gxp, offs, O2); + ldx_entry(gxp, offs, O1); + ldx_entry(gxp, offs, O0); + + __ save(SP, -176, SP); + + const Register addr = gxp; // Alright to reuse 'gxp'. + + // Dispatch relative current PC, into instruction table below. + __ rdpc(addr); + __ add(addr, 16, addr); + __ jmp(addr, disp); + __ delayed()->clr(offs); + + ldd_entry(gyp, offs, F58); + ldd_entry(gyp, offs, F56); + ldd_entry(gyp, offs, F54); + ldd_entry(gyp, offs, F52); + ldd_entry(gyp, offs, F50); + ldd_entry(gyp, offs, F48); + ldd_entry(gyp, offs, F46); + ldd_entry(gyp, offs, F44); + ldd_entry(gyp, offs, F42); + ldd_entry(gyp, offs, F40); + ldd_entry(gyp, offs, F38); + ldd_entry(gyp, offs, F36); + ldd_entry(gyp, offs, F34); + ldd_entry(gyp, offs, F32); + ldd_entry(gyp, offs, F30); + ldd_entry(gyp, offs, F28); + ldd_entry(gyp, offs, F26); + ldd_entry(gyp, offs, F24); + ldx_entry(gyp, offs, O5); + ldx_entry(gyp, offs, O4); + ldx_entry(gyp, offs, O3); + ldx_entry(gyp, offs, O2); + ldx_entry(gyp, offs, O1); + ldx_entry(gyp, offs, O0); + ldx_entry(gyp, offs, L7); + ldx_entry(gyp, offs, L6); + ldx_entry(gyp, offs, L5); + ldx_entry(gyp, offs, L4); + ldx_entry(gyp, offs, L3); + ldx_entry(gyp, offs, L2); + ldx_entry(gyp, offs, L1); + ldx_entry(gyp, offs, L0); + + __ save(SP, -176, SP); + __ save(SP, -176, SP); + __ save(SP, -176, SP); + __ save(SP, -176, SP); + __ save(SP, -176, SP); + + Label L_mpmul_restore_4, L_mpmul_restore_3, L_mpmul_restore_2; + Label L_mpmul_restore_1, L_mpmul_restore_0; + + // Dispatch relative current PC, into instruction table below. + __ rdpc(addr); + __ add(addr, 16, addr); + __ jmp(addr, disp); + __ delayed()->clr(offs); + + mpmul_entry(31, L_mpmul_restore_0); + mpmul_entry(30, L_mpmul_restore_0); + mpmul_entry(29, L_mpmul_restore_0); + mpmul_entry(28, L_mpmul_restore_0); + mpmul_entry(27, L_mpmul_restore_1); + mpmul_entry(26, L_mpmul_restore_1); + mpmul_entry(25, L_mpmul_restore_1); + mpmul_entry(24, L_mpmul_restore_1); + mpmul_entry(23, L_mpmul_restore_1); + mpmul_entry(22, L_mpmul_restore_1); + mpmul_entry(21, L_mpmul_restore_1); + mpmul_entry(20, L_mpmul_restore_2); + mpmul_entry(19, L_mpmul_restore_2); + mpmul_entry(18, L_mpmul_restore_2); + mpmul_entry(17, L_mpmul_restore_2); + mpmul_entry(16, L_mpmul_restore_2); + mpmul_entry(15, L_mpmul_restore_2); + mpmul_entry(14, L_mpmul_restore_2); + mpmul_entry(13, L_mpmul_restore_3); + mpmul_entry(12, L_mpmul_restore_3); + mpmul_entry(11, L_mpmul_restore_3); + mpmul_entry(10, L_mpmul_restore_3); + mpmul_entry( 9, L_mpmul_restore_3); + mpmul_entry( 8, L_mpmul_restore_3); + mpmul_entry( 7, L_mpmul_restore_3); + mpmul_entry( 6, L_mpmul_restore_4); + mpmul_entry( 5, L_mpmul_restore_4); + mpmul_entry( 4, L_mpmul_restore_4); + mpmul_entry( 3, L_mpmul_restore_4); + mpmul_entry( 2, L_mpmul_restore_4); + mpmul_entry( 1, L_mpmul_restore_4); + mpmul_entry( 0, L_mpmul_restore_4); + + Label L_z31, L_z30, L_z29, L_z28, L_z27, L_z26, L_z25, L_z24; + Label L_z23, L_z22, L_z21, L_z20, L_z19, L_z18, L_z17, L_z16; + Label L_z15, L_z14, L_z13, L_z12, L_z11, L_z10, L_z09, L_z08; + Label L_z07, L_z06, L_z05, L_z04, L_z03, L_z02, L_z01, L_z00; + + Label L_zst_base; // Store sequence base address. + __ bind(L_zst_base); + + stx_entry(L_z31, L7, L6, gzp, offs); + stx_entry(L_z30, L5, L4, gzp, offs); + stx_entry(L_z29, L3, L2, gzp, offs); + stx_entry(L_z28, L1, L0, gzp, offs); + __ restore(); + stx_entry(L_z27, O5, O4, gzp, offs); + stx_entry(L_z26, O3, O2, gzp, offs); + stx_entry(L_z25, O1, O0, gzp, offs); + stx_entry(L_z24, L7, L6, gzp, offs); + stx_entry(L_z23, L5, L4, gzp, offs); + stx_entry(L_z22, L3, L2, gzp, offs); + stx_entry(L_z21, L1, L0, gzp, offs); + __ restore(); + stx_entry(L_z20, O5, O4, gzp, offs); + stx_entry(L_z19, O3, O2, gzp, offs); + stx_entry(L_z18, O1, O0, gzp, offs); + stx_entry(L_z17, L7, L6, gzp, offs); + stx_entry(L_z16, L5, L4, gzp, offs); + stx_entry(L_z15, L3, L2, gzp, offs); + stx_entry(L_z14, L1, L0, gzp, offs); + __ restore(); + stx_entry(L_z13, O5, O4, gzp, offs); + stx_entry(L_z12, O3, O2, gzp, offs); + stx_entry(L_z11, O1, O0, gzp, offs); + stx_entry(L_z10, L7, L6, gzp, offs); + stx_entry(L_z09, L5, L4, gzp, offs); + stx_entry(L_z08, L3, L2, gzp, offs); + stx_entry(L_z07, L1, L0, gzp, offs); + __ restore(); + stx_entry(L_z06, O5, O4, gzp, offs); + stx_entry(L_z05, O3, O2, gzp, offs); + stx_entry(L_z04, O1, O0, gzp, offs); + stx_entry(L_z03, L7, L6, gzp, offs); + stx_entry(L_z02, L5, L4, gzp, offs); + stx_entry(L_z01, L3, L2, gzp, offs); + stx_entry(L_z00, L1, L0, gzp, offs); + + __ restore(); + __ restore(); + // Exit out of 'mpmul' routine, back to multiplyToLen. + __ ba_short(L_exit); + + Label L_zst_offs; + __ bind(L_zst_offs); + + offs_entry(L_z31, L_zst_base); // index 31: 2048x2048 + offs_entry(L_z30, L_zst_base); + offs_entry(L_z29, L_zst_base); + offs_entry(L_z28, L_zst_base); + offs_entry(L_z27, L_zst_base); + offs_entry(L_z26, L_zst_base); + offs_entry(L_z25, L_zst_base); + offs_entry(L_z24, L_zst_base); + offs_entry(L_z23, L_zst_base); + offs_entry(L_z22, L_zst_base); + offs_entry(L_z21, L_zst_base); + offs_entry(L_z20, L_zst_base); + offs_entry(L_z19, L_zst_base); + offs_entry(L_z18, L_zst_base); + offs_entry(L_z17, L_zst_base); + offs_entry(L_z16, L_zst_base); + offs_entry(L_z15, L_zst_base); + offs_entry(L_z14, L_zst_base); + offs_entry(L_z13, L_zst_base); + offs_entry(L_z12, L_zst_base); + offs_entry(L_z11, L_zst_base); + offs_entry(L_z10, L_zst_base); + offs_entry(L_z09, L_zst_base); + offs_entry(L_z08, L_zst_base); + offs_entry(L_z07, L_zst_base); + offs_entry(L_z06, L_zst_base); + offs_entry(L_z05, L_zst_base); + offs_entry(L_z04, L_zst_base); + offs_entry(L_z03, L_zst_base); + offs_entry(L_z02, L_zst_base); + offs_entry(L_z01, L_zst_base); + offs_entry(L_z00, L_zst_base); // index 0: 64x64 + + __ bind(L_mpmul_restore_4); + __ restore(); + __ bind(L_mpmul_restore_3); + __ restore(); + __ bind(L_mpmul_restore_2); + __ restore(); + __ bind(L_mpmul_restore_1); + __ restore(); + __ bind(L_mpmul_restore_0); + + // Dispatch via offset vector entry, into z-store sequence. + Label L_zst_rdpc; + __ bind(L_zst_rdpc); + + assert(L_zst_base.is_bound(), "must be"); + assert(L_zst_offs.is_bound(), "must be"); + assert(L_zst_rdpc.is_bound(), "must be"); + + int dbase = L_zst_rdpc.loc_pos() - L_zst_base.loc_pos(); + int doffs = L_zst_rdpc.loc_pos() - L_zst_offs.loc_pos(); + + temp = gyp; // Alright to reuse 'gyp'. + + __ rdpc(addr); + __ sub(addr, doffs, temp); + __ srlx(disp, 1, disp); + __ lduw(temp, disp, offs); + __ sub(addr, dbase, temp); + __ jmp(temp, offs); + __ delayed()->clr(offs); + } + + void gen_mult_64x64(Register xp, Register xn, + Register yp, Register yn, + Register zp, Register zn, Label &L_exit) + { + // Assuming that a stack frame has already been created, i.e. local and + // output registers are available for immediate use. + + const Register ri = L0; // Outer loop index, xv[i] + const Register rj = L1; // Inner loop index, yv[j] + const Register rk = L2; // Output loop index, zv[k] + const Register rx = L4; // x-vector datum [i] + const Register ry = L5; // y-vector datum [j] + const Register rz = L6; // z-vector datum [k] + const Register rc = L7; // carry over (to z-vector datum [k-1]) + + const Register lop = O0; // lo-64b product + const Register hip = O1; // hi-64b product + + const Register zero = G0; + + Label L_loop_i, L_exit_loop_i; + Label L_loop_j; + Label L_loop_i2, L_exit_loop_i2; + + __ srlx(xn, 1, xn); // index for u32 to u64 ditto + __ srlx(yn, 1, yn); // index for u32 to u64 ditto + __ srlx(zn, 1, zn); // index for u32 to u64 ditto + __ dec(xn); // Adjust [0..(N/2)-1] + __ dec(yn); + __ dec(zn); + __ clr(rc); // u64 c = 0 + __ sllx(xn, 3, ri); // int i = xn (byte offset i = 8*xn) + __ sllx(yn, 3, rj); // int j = yn (byte offset i = 8*xn) + __ sllx(zn, 3, rk); // int k = zn (byte offset k = 8*zn) + __ ldx(yp, rj, ry); // u64 y = yp[yn] + + // for (int i = xn; i >= 0; i--) + __ bind(L_loop_i); + + __ cmp_and_br_short(ri, 0, // i >= 0 + Assembler::less, Assembler::pn, L_exit_loop_i); + __ ldx(xp, ri, rx); // x = xp[i] + __ mulx(rx, ry, lop); // lo-64b-part of result 64x64 + __ umulxhi(rx, ry, hip); // hi-64b-part of result 64x64 + __ addcc(rc, lop, lop); // Accumulate lower order bits (producing carry) + __ addxc(hip, zero, rc); // carry over to next datum [k-1] + __ stx(lop, zp, rk); // z[k] = lop + __ dec(rk, 8); // k-- + __ dec(ri, 8); // i-- + __ ba_short(L_loop_i); + + __ bind(L_exit_loop_i); + __ stx(rc, zp, rk); // z[k] = c + + // for (int j = yn - 1; j >= 0; j--) + __ sllx(yn, 3, rj); // int j = yn - 1 (byte offset j = 8*yn) + __ dec(rj, 8); + + __ bind(L_loop_j); + + __ cmp_and_br_short(rj, 0, // j >= 0 + Assembler::less, Assembler::pn, L_exit); + __ clr(rc); // u64 c = 0 + __ ldx(yp, rj, ry); // u64 y = yp[j] + + // for (int i = xn, k = --zn; i >= 0; i--) + __ dec(zn); // --zn + __ sllx(xn, 3, ri); // int i = xn (byte offset i = 8*xn) + __ sllx(zn, 3, rk); // int k = zn (byte offset k = 8*zn) + + __ bind(L_loop_i2); + + __ cmp_and_br_short(ri, 0, // i >= 0 + Assembler::less, Assembler::pn, L_exit_loop_i2); + __ ldx(xp, ri, rx); // x = xp[i] + __ ldx(zp, rk, rz); // z = zp[k], accumulator + __ mulx(rx, ry, lop); // lo-64b-part of result 64x64 + __ umulxhi(rx, ry, hip); // hi-64b-part of result 64x64 + __ addcc(rz, rc, rz); // Accumulate lower order bits, + __ addxc(hip, zero, rc); // Accumulate higher order bits to carry + __ addcc(rz, lop, rz); // z += lo(p) + c + __ addxc(rc, zero, rc); + __ stx(rz, zp, rk); // zp[k] = z + __ dec(rk, 8); // k-- + __ dec(ri, 8); // i-- + __ ba_short(L_loop_i2); + + __ bind(L_exit_loop_i2); + __ stx(rc, zp, rk); // z[k] = c + __ dec(rj, 8); // j-- + __ ba_short(L_loop_j); + } + + void gen_mult_64x64_unaligned(Register xp, Register xn, + Register yp, Register yn, + Register zp, Register zn, Label &L_exit) + { + // Assuming that a stack frame has already been created, i.e. local and + // output registers are available for use. + + const Register xpc = L0; // Outer loop cursor, xp[i] + const Register ypc = L1; // Inner loop cursor, yp[j] + const Register zpc = L2; // Output loop cursor, zp[k] + const Register rx = L4; // x-vector datum [i] + const Register ry = L5; // y-vector datum [j] + const Register rz = L6; // z-vector datum [k] + const Register rc = L7; // carry over (to z-vector datum [k-1]) + const Register rt = O2; + + const Register lop = O0; // lo-64b product + const Register hip = O1; // hi-64b product + + const Register zero = G0; + + Label L_loop_i, L_exit_loop_i; + Label L_loop_j; + Label L_loop_i2, L_exit_loop_i2; + + __ srlx(xn, 1, xn); // index for u32 to u64 ditto + __ srlx(yn, 1, yn); // index for u32 to u64 ditto + __ srlx(zn, 1, zn); // index for u32 to u64 ditto + __ dec(xn); // Adjust [0..(N/2)-1] + __ dec(yn); + __ dec(zn); + __ clr(rc); // u64 c = 0 + __ sllx(xn, 3, xpc); // u32* xpc = &xp[xn] (byte offset 8*xn) + __ add(xp, xpc, xpc); + __ sllx(yn, 3, ypc); // u32* ypc = &yp[yn] (byte offset 8*yn) + __ add(yp, ypc, ypc); + __ sllx(zn, 3, zpc); // u32* zpc = &zp[zn] (byte offset 8*zn) + __ add(zp, zpc, zpc); + __ lduw(ypc, 0, rt); // u64 y = yp[yn] + __ lduw(ypc, 4, ry); // ... + __ sllx(rt, 32, rt); + __ or3(rt, ry, ry); + + // for (int i = xn; i >= 0; i--) + __ bind(L_loop_i); + + __ cmp_and_br_short(xpc, xp,// i >= 0 + Assembler::less, Assembler::pn, L_exit_loop_i); + __ lduw(xpc, 0, rt); // u64 x = xp[i] + __ lduw(xpc, 4, rx); // ... + __ sllx(rt, 32, rt); + __ or3(rt, rx, rx); + __ mulx(rx, ry, lop); // lo-64b-part of result 64x64 + __ umulxhi(rx, ry, hip); // hi-64b-part of result 64x64 + __ addcc(rc, lop, lop); // Accumulate lower order bits (producing carry) + __ addxc(hip, zero, rc); // carry over to next datum [k-1] + __ srlx(lop, 32, rt); + __ stw(rt, zpc, 0); // z[k] = lop + __ stw(lop, zpc, 4); // ... + __ dec(zpc, 8); // k-- (zpc--) + __ dec(xpc, 8); // i-- (xpc--) + __ ba_short(L_loop_i); + + __ bind(L_exit_loop_i); + __ srlx(rc, 32, rt); + __ stw(rt, zpc, 0); // z[k] = c + __ stw(rc, zpc, 4); + + // for (int j = yn - 1; j >= 0; j--) + __ sllx(yn, 3, ypc); // u32* ypc = &yp[yn] (byte offset 8*yn) + __ add(yp, ypc, ypc); + __ dec(ypc, 8); // yn - 1 (ypc--) + + __ bind(L_loop_j); + + __ cmp_and_br_short(ypc, yp,// j >= 0 + Assembler::less, Assembler::pn, L_exit); + __ clr(rc); // u64 c = 0 + __ lduw(ypc, 0, rt); // u64 y = yp[j] (= *ypc) + __ lduw(ypc, 4, ry); // ... + __ sllx(rt, 32, rt); + __ or3(rt, ry, ry); + + // for (int i = xn, k = --zn; i >= 0; i--) + __ sllx(xn, 3, xpc); // u32* xpc = &xp[xn] (byte offset 8*xn) + __ add(xp, xpc, xpc); + __ dec(zn); // --zn + __ sllx(zn, 3, zpc); // u32* zpc = &zp[zn] (byte offset 8*zn) + __ add(zp, zpc, zpc); + + __ bind(L_loop_i2); + + __ cmp_and_br_short(xpc, xp,// i >= 0 + Assembler::less, Assembler::pn, L_exit_loop_i2); + __ lduw(xpc, 0, rt); // u64 x = xp[i] (= *xpc) + __ lduw(xpc, 4, rx); // ... + __ sllx(rt, 32, rt); + __ or3(rt, rx, rx); + + __ lduw(zpc, 0, rt); // u64 z = zp[k] (= *zpc) + __ lduw(zpc, 4, rz); // ... + __ sllx(rt, 32, rt); + __ or3(rt, rz, rz); + + __ mulx(rx, ry, lop); // lo-64b-part of result 64x64 + __ umulxhi(rx, ry, hip); // hi-64b-part of result 64x64 + __ addcc(rz, rc, rz); // Accumulate lower order bits... + __ addxc(hip, zero, rc); // Accumulate higher order bits to carry + __ addcc(rz, lop, rz); // ... z += lo(p) + c + __ addxccc(rc, zero, rc); + __ srlx(rz, 32, rt); + __ stw(rt, zpc, 0); // zp[k] = z (*zpc = z) + __ stw(rz, zpc, 4); + __ dec(zpc, 8); // k-- (zpc--) + __ dec(xpc, 8); // i-- (xpc--) + __ ba_short(L_loop_i2); + + __ bind(L_exit_loop_i2); + __ srlx(rc, 32, rt); + __ stw(rt, zpc, 0); // z[k] = c + __ stw(rc, zpc, 4); + __ dec(ypc, 8); // j-- (ypc--) + __ ba_short(L_loop_j); + } + + void gen_mult_32x32(Register xp, Register xn, + Register yp, Register yn, + Register zp, Register zn, Label &L_exit) + { + // Assuming that a stack frame has already been created, i.e. local and + // output registers are available for use. + + const Register ri = L0; // Outer loop index, xv[i] + const Register rj = L1; // Inner loop index, yv[j] + const Register rk = L2; // Output loop index, zv[k] + const Register rx = L4; // x-vector datum [i] + const Register ry = L5; // y-vector datum [j] + const Register rz = L6; // z-vector datum [k] + const Register rc = L7; // carry over (to z-vector datum [k-1]) + + const Register p64 = O0; // 64b product + const Register z65 = O1; // carry+64b accumulator + const Register c65 = O2; // carry at bit 65 + const Register c33 = O2; // carry at bit 33 (after shift) + + const Register zero = G0; + + Label L_loop_i, L_exit_loop_i; + Label L_loop_j; + Label L_loop_i2, L_exit_loop_i2; + + __ dec(xn); // Adjust [0..N-1] + __ dec(yn); + __ dec(zn); + __ clr(rc); // u32 c = 0 + __ sllx(xn, 2, ri); // int i = xn (byte offset i = 4*xn) + __ sllx(yn, 2, rj); // int j = yn (byte offset i = 4*xn) + __ sllx(zn, 2, rk); // int k = zn (byte offset k = 4*zn) + __ lduw(yp, rj, ry); // u32 y = yp[yn] + + // for (int i = xn; i >= 0; i--) + __ bind(L_loop_i); + + __ cmp_and_br_short(ri, 0, // i >= 0 + Assembler::less, Assembler::pn, L_exit_loop_i); + __ lduw(xp, ri, rx); // x = xp[i] + __ mulx(rx, ry, p64); // 64b result of 32x32 + __ addcc(rc, p64, z65); // Accumulate to 65 bits (producing carry) + __ addxc(zero, zero, c65); // Materialise carry (in bit 65) into lsb, + __ sllx(c65, 32, c33); // and shift into bit 33 + __ srlx(z65, 32, rc); // carry = c33 | hi(z65) >> 32 + __ add(c33, rc, rc); // carry over to next datum [k-1] + __ stw(z65, zp, rk); // z[k] = lo(z65) + __ dec(rk, 4); // k-- + __ dec(ri, 4); // i-- + __ ba_short(L_loop_i); + + __ bind(L_exit_loop_i); + __ stw(rc, zp, rk); // z[k] = c + + // for (int j = yn - 1; j >= 0; j--) + __ sllx(yn, 2, rj); // int j = yn - 1 (byte offset j = 4*yn) + __ dec(rj, 4); + + __ bind(L_loop_j); + + __ cmp_and_br_short(rj, 0, // j >= 0 + Assembler::less, Assembler::pn, L_exit); + __ clr(rc); // u32 c = 0 + __ lduw(yp, rj, ry); // u32 y = yp[j] + + // for (int i = xn, k = --zn; i >= 0; i--) + __ dec(zn); // --zn + __ sllx(xn, 2, ri); // int i = xn (byte offset i = 4*xn) + __ sllx(zn, 2, rk); // int k = zn (byte offset k = 4*zn) + + __ bind(L_loop_i2); + + __ cmp_and_br_short(ri, 0, // i >= 0 + Assembler::less, Assembler::pn, L_exit_loop_i2); + __ lduw(xp, ri, rx); // x = xp[i] + __ lduw(zp, rk, rz); // z = zp[k], accumulator + __ mulx(rx, ry, p64); // 64b result of 32x32 + __ add(rz, rc, rz); // Accumulate lower order bits, + __ addcc(rz, p64, z65); // z += lo(p64) + c + __ addxc(zero, zero, c65); // Materialise carry (in bit 65) into lsb, + __ sllx(c65, 32, c33); // and shift into bit 33 + __ srlx(z65, 32, rc); // carry = c33 | hi(z65) >> 32 + __ add(c33, rc, rc); // carry over to next datum [k-1] + __ stw(z65, zp, rk); // zp[k] = lo(z65) + __ dec(rk, 4); // k-- + __ dec(ri, 4); // i-- + __ ba_short(L_loop_i2); + + __ bind(L_exit_loop_i2); + __ stw(rc, zp, rk); // z[k] = c + __ dec(rj, 4); // j-- + __ ba_short(L_loop_j); + } + + void generate_initial() { // Generates all stubs and initializes the entry points @@ -5073,8 +5839,14 @@ class StubGenerator: public StubCodeGenerator { if (UseAdler32Intrinsics) { StubRoutines::_updateBytesAdler32 = generate_updateBytesAdler32(); } - } +#ifdef COMPILER2 + // Intrinsics supported by C2 only: + if (UseMultiplyToLenIntrinsic) { + StubRoutines::_multiplyToLen = generate_multiplyToLen(); + } +#endif // COMPILER2 + } public: StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) { diff --git a/src/hotspot/cpu/sparc/stubRoutines_sparc.hpp b/src/hotspot/cpu/sparc/stubRoutines_sparc.hpp index eb6c909c0b3..d41c5b8e4ae 100644 --- a/src/hotspot/cpu/sparc/stubRoutines_sparc.hpp +++ b/src/hotspot/cpu/sparc/stubRoutines_sparc.hpp @@ -41,7 +41,7 @@ static bool returns_to_call_stub(address return_pc) { enum /* platform_dependent_constants */ { // %%%%%%%% May be able to shrink this a lot code_size1 = 20000, // simply increase if too small (assembler will crash if too small) - code_size2 = 27000 // simply increase if too small (assembler will crash if too small) + code_size2 = 29000 // simply increase if too small (assembler will crash if too small) }; class Sparc { diff --git a/src/hotspot/cpu/sparc/templateTable_sparc.cpp b/src/hotspot/cpu/sparc/templateTable_sparc.cpp index f8d861a1df0..8683c35e635 100644 --- a/src/hotspot/cpu/sparc/templateTable_sparc.cpp +++ b/src/hotspot/cpu/sparc/templateTable_sparc.cpp @@ -2049,6 +2049,7 @@ void TemplateTable::load_field_cp_cache_entry(Register Robj, __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f1_offset(), Robj); const int mirror_offset = in_bytes(Klass::java_mirror_offset()); __ ld_ptr( Robj, mirror_offset, Robj); + __ resolve_oop_handle(Robj); } } diff --git a/src/hotspot/cpu/sparc/vmStructs_sparc.hpp b/src/hotspot/cpu/sparc/vmStructs_sparc.hpp index aa21dbdb2db..d678b4dbfd4 100644 --- a/src/hotspot/cpu/sparc/vmStructs_sparc.hpp +++ b/src/hotspot/cpu/sparc/vmStructs_sparc.hpp @@ -101,6 +101,14 @@ declare_constant(VM_Version::ISA_XMONT) \ declare_constant(VM_Version::ISA_PAUSE_NSEC) \ declare_constant(VM_Version::ISA_VAMASK) \ + declare_constant(VM_Version::ISA_SPARC6) \ + declare_constant(VM_Version::ISA_DICTUNP) \ + declare_constant(VM_Version::ISA_FPCMPSHL) \ + declare_constant(VM_Version::ISA_RLE) \ + declare_constant(VM_Version::ISA_SHA3) \ + declare_constant(VM_Version::ISA_VIS3C) \ + declare_constant(VM_Version::ISA_SPARC5B) \ + declare_constant(VM_Version::ISA_MME) \ declare_constant(VM_Version::CPU_FAST_IDIV) \ declare_constant(VM_Version::CPU_FAST_RDPC) \ declare_constant(VM_Version::CPU_FAST_BIS) \ diff --git a/src/hotspot/cpu/sparc/vm_version_sparc.cpp b/src/hotspot/cpu/sparc/vm_version_sparc.cpp index 37203221f71..b5ef619c35e 100644 --- a/src/hotspot/cpu/sparc/vm_version_sparc.cpp +++ b/src/hotspot/cpu/sparc/vm_version_sparc.cpp @@ -103,7 +103,7 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(AllocatePrefetchInstr, 1); } else if (has_sparc5()) { - // Use prefetch instruction to avoid partial RAW issue on Core S4 processors, + // Use prefetch instruction to avoid partial RAW issue on Core C4 processors, // also use prefetch style 3. FLAG_SET_DEFAULT(AllocatePrefetchInstr, 0); if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { @@ -128,7 +128,7 @@ void VM_Version::initialize() { // We increase the number of prefetched cache lines, to use just a bit more // aggressive approach, when the L2-cache line size is small (32 bytes), or - // when running on newer processor implementations, such as the Core S4. + // when running on newer processor implementations, such as the Core C4. bool inc_prefetch = cache_line_size > 0 && (cache_line_size < 64 || has_sparc5()); if (inc_prefetch) { @@ -168,6 +168,16 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseCBCond, false); } + // Use 'mpmul' instruction if available. + if (has_mpmul()) { + if (FLAG_IS_DEFAULT(UseMPMUL)) { + FLAG_SET_DEFAULT(UseMPMUL, true); + } + } else if (UseMPMUL) { + warning("MPMUL instruction is not available on this CPU"); + FLAG_SET_DEFAULT(UseMPMUL, false); + } + assert(BlockZeroingLowLimit > 0, "invalid value"); if (has_blk_zeroing() && cache_line_size > 0) { @@ -208,7 +218,9 @@ void VM_Version::initialize() { char buf[512]; jio_snprintf(buf, sizeof(buf), - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" + "%s%s%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s%s%s" + "%s%s%s%s%s%s%s", (has_v9() ? "v9" : ""), (has_popc() ? ", popc" : ""), (has_vis1() ? ", vis1" : ""), @@ -241,6 +253,16 @@ void VM_Version::initialize() { (has_pause_nsec() ? ", pause_nsec" : ""), (has_vamask() ? ", vamask" : ""), + (has_sparc6() ? ", sparc6" : ""), + (has_dictunp() ? ", dictunp" : ""), + (has_fpcmpshl() ? ", fpcmpshl" : ""), + (has_rle() ? ", rle" : ""), + (has_sha3() ? ", sha3" : ""), + (has_athena_plus2()? ", athena_plus2" : ""), + (has_vis3c() ? ", vis3c" : ""), + (has_sparc5b() ? ", sparc5b" : ""), + (has_mme() ? ", mme" : ""), + (has_fast_idiv() ? ", *idiv" : ""), (has_fast_rdpc() ? ", *rdpc" : ""), (has_fast_bis() ? ", *bis" : ""), @@ -409,6 +431,15 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); } + if (UseVIS > 2) { + if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { + FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true); + } + } else if (UseMultiplyToLenIntrinsic) { + warning("SPARC multiplyToLen intrinsics require VIS3 instructions support. Intrinsics will be disabled"); + FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false); + } + if (UseVectorizedMismatchIntrinsic) { warning("UseVectorizedMismatchIntrinsic specified, but not available on this CPU."); FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); diff --git a/src/hotspot/cpu/sparc/vm_version_sparc.hpp b/src/hotspot/cpu/sparc/vm_version_sparc.hpp index 58e8283d6ee..04ff200f439 100644 --- a/src/hotspot/cpu/sparc/vm_version_sparc.hpp +++ b/src/hotspot/cpu/sparc/vm_version_sparc.hpp @@ -67,6 +67,16 @@ protected: ISA_PAUSE_NSEC, ISA_VAMASK, + ISA_SPARC6, + ISA_DICTUNP, + ISA_FPCMPSHL, + ISA_RLE, + ISA_SHA3, + ISA_FJATHPLUS2, + ISA_VIS3C, + ISA_SPARC5B, + ISA_MME, + // Synthesised properties: CPU_FAST_IDIV, @@ -79,7 +89,7 @@ protected: }; private: - enum { ISA_last_feature = ISA_VAMASK, + enum { ISA_last_feature = ISA_MME, CPU_last_feature = CPU_BLK_ZEROING }; enum { @@ -119,6 +129,16 @@ private: ISA_pause_nsec_msk = UINT64_C(1) << ISA_PAUSE_NSEC, ISA_vamask_msk = UINT64_C(1) << ISA_VAMASK, + ISA_sparc6_msk = UINT64_C(1) << ISA_SPARC6, + ISA_dictunp_msk = UINT64_C(1) << ISA_DICTUNP, + ISA_fpcmpshl_msk = UINT64_C(1) << ISA_FPCMPSHL, + ISA_rle_msk = UINT64_C(1) << ISA_RLE, + ISA_sha3_msk = UINT64_C(1) << ISA_SHA3, + ISA_fjathplus2_msk = UINT64_C(1) << ISA_FJATHPLUS2, + ISA_vis3c_msk = UINT64_C(1) << ISA_VIS3C, + ISA_sparc5b_msk = UINT64_C(1) << ISA_SPARC5B, + ISA_mme_msk = UINT64_C(1) << ISA_MME, + CPU_fast_idiv_msk = UINT64_C(1) << CPU_FAST_IDIV, CPU_fast_rdpc_msk = UINT64_C(1) << CPU_FAST_RDPC, CPU_fast_bis_msk = UINT64_C(1) << CPU_FAST_BIS, @@ -153,40 +173,51 @@ private: * UltraSPARC T2+: (Victoria Falls, etc.) * SPARC-V9, VIS, VIS2, ASI_BIS, POPC (Crypto/hash in SPU) * - * UltraSPARC T3: (Rainbow Falls/S2) + * UltraSPARC T3: (Rainbow Falls/C2) * SPARC-V9, VIS, VIS2, ASI_BIS, POPC (Crypto/hash in SPU) * - * Oracle SPARC T4/T5/M5: (Core S3) + * Oracle SPARC T4/T5/M5: (Core C3) * SPARC-V9, VIS, VIS2, VIS3, ASI_BIS, HPC, POPC, FMAF, IMA, PAUSE, CBCOND, * AES, DES, Kasumi, Camellia, MD5, SHA1, SHA256, SHA512, CRC32C, MONT, MPMUL * - * Oracle SPARC M7: (Core S4) + * Oracle SPARC M7: (Core C4) * SPARC-V9, VIS, VIS2, VIS3, ASI_BIS, HPC, POPC, FMAF, IMA, PAUSE, CBCOND, * AES, DES, Camellia, MD5, SHA1, SHA256, SHA512, CRC32C, MONT, MPMUL, VIS3b, * ADI, SPARC5, MWAIT, XMPMUL, XMONT, PAUSE_NSEC, VAMASK * + * Oracle SPARC M8: (Core C5) + * SPARC-V9, VIS, VIS2, VIS3, ASI_BIS, HPC, POPC, FMAF, IMA, PAUSE, CBCOND, + * AES, DES, Camellia, MD5, SHA1, SHA256, SHA512, CRC32C, MONT, MPMUL, VIS3b, + * ADI, SPARC5, MWAIT, XMPMUL, XMONT, PAUSE_NSEC, VAMASK, SPARC6, FPCMPSHL, + * DICTUNP, RLE, SHA3, MME + * + * NOTE: Oracle Number support ignored. */ enum { niagara1_msk = ISA_v9_msk | ISA_vis1_msk | ISA_blk_init_msk, niagara2_msk = niagara1_msk | ISA_popc_msk, - core_S2_msk = niagara2_msk | ISA_vis2_msk, + core_C2_msk = niagara2_msk | ISA_vis2_msk, - core_S3_msk = core_S2_msk | ISA_fmaf_msk | ISA_vis3_msk | ISA_hpc_msk | + core_C3_msk = core_C2_msk | ISA_fmaf_msk | ISA_vis3_msk | ISA_hpc_msk | ISA_ima_msk | ISA_aes_msk | ISA_des_msk | ISA_kasumi_msk | ISA_camellia_msk | ISA_md5_msk | ISA_sha1_msk | ISA_sha256_msk | ISA_sha512_msk | ISA_mpmul_msk | ISA_mont_msk | ISA_pause_msk | ISA_cbcond_msk | ISA_crc32c_msk, - core_S4_msk = core_S3_msk - ISA_kasumi_msk | + core_C4_msk = core_C3_msk - ISA_kasumi_msk | ISA_vis3b_msk | ISA_adi_msk | ISA_sparc5_msk | ISA_mwait_msk | ISA_xmpmul_msk | ISA_xmont_msk | ISA_pause_nsec_msk | ISA_vamask_msk, + core_C5_msk = core_C4_msk | ISA_sparc6_msk | ISA_dictunp_msk | + ISA_fpcmpshl_msk | ISA_rle_msk | ISA_sha3_msk | ISA_mme_msk, + ultra_sparc_t1_msk = niagara1_msk, ultra_sparc_t2_msk = niagara2_msk, - ultra_sparc_t3_msk = core_S2_msk, - ultra_sparc_m5_msk = core_S3_msk, // NOTE: First out-of-order pipeline. - ultra_sparc_m7_msk = core_S4_msk + ultra_sparc_t3_msk = core_C2_msk, + ultra_sparc_m5_msk = core_C3_msk, // NOTE: First out-of-order pipeline. + ultra_sparc_m7_msk = core_C4_msk, + ultra_sparc_m8_msk = core_C5_msk }; static uint _L2_data_cache_line_size; @@ -247,6 +278,16 @@ public: static bool has_pause_nsec() { return (_features & ISA_pause_nsec_msk) != 0; } static bool has_vamask() { return (_features & ISA_vamask_msk) != 0; } + static bool has_sparc6() { return (_features & ISA_sparc6_msk) != 0; } + static bool has_dictunp() { return (_features & ISA_dictunp_msk) != 0; } + static bool has_fpcmpshl() { return (_features & ISA_fpcmpshl_msk) != 0; } + static bool has_rle() { return (_features & ISA_rle_msk) != 0; } + static bool has_sha3() { return (_features & ISA_sha3_msk) != 0; } + static bool has_athena_plus2() { return (_features & ISA_fjathplus2_msk) != 0; } + static bool has_vis3c() { return (_features & ISA_vis3c_msk) != 0; } + static bool has_sparc5b() { return (_features & ISA_sparc5b_msk) != 0; } + static bool has_mme() { return (_features & ISA_mme_msk) != 0; } + static bool has_fast_idiv() { return (_features & CPU_fast_idiv_msk) != 0; } static bool has_fast_rdpc() { return (_features & CPU_fast_rdpc_msk) != 0; } static bool has_fast_bis() { return (_features & CPU_fast_bis_msk) != 0; } diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index f747e41e522..37c4c6dfa3e 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -2571,7 +2571,7 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, if (opr2->is_single_cpu()) { // cpu register - cpu register if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY) { - __ cmpptr(reg1, opr2->as_register()); + __ cmpoop(reg1, opr2->as_register()); } else { assert(opr2->type() != T_OBJECT && opr2->type() != T_ARRAY, "cmp int, oop?"); __ cmpl(reg1, opr2->as_register()); @@ -2579,7 +2579,7 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, } else if (opr2->is_stack()) { // cpu register - stack if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY) { - __ cmpptr(reg1, frame_map()->address_for_slot(opr2->single_stack_ix())); + __ cmpoop(reg1, frame_map()->address_for_slot(opr2->single_stack_ix())); } else { __ cmpl(reg1, frame_map()->address_for_slot(opr2->single_stack_ix())); } @@ -2594,12 +2594,7 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, if (o == NULL) { __ cmpptr(reg1, (int32_t)NULL_WORD); } else { -#ifdef _LP64 - __ movoop(rscratch1, o); - __ cmpptr(reg1, rscratch1); -#else - __ cmpoop(reg1, c->as_jobject()); -#endif // _LP64 + __ cmpoop(reg1, o); } } else { fatal("unexpected type: %s", basictype_to_str(c->type())); @@ -2709,7 +2704,7 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, #ifdef _LP64 // %%% Make this explode if addr isn't reachable until we figure out a // better strategy by giving noreg as the temp for as_Address - __ cmpptr(rscratch1, as_Address(addr, noreg)); + __ cmpoop(rscratch1, as_Address(addr, noreg)); #else __ cmpoop(as_Address(addr), c->as_jobject()); #endif // _LP64 @@ -3487,13 +3482,9 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { Register mdo = op->mdo()->as_register(); __ mov_metadata(mdo, md->constant_encoding()); Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); - Bytecodes::Code bc = method->java_code_at_bci(bci); - const bool callee_is_static = callee->is_loaded() && callee->is_static(); // Perform additional virtual call profiling for invokevirtual and // invokeinterface bytecodes - if ((bc == Bytecodes::_invokevirtual || bc == Bytecodes::_invokeinterface) && - !callee_is_static && // required for optimized MH invokes - C1ProfileVirtualCalls) { + if (op->should_profile_receiver_type()) { assert(op->recv()->is_single_cpu(), "recv must be allocated"); Register recv = op->recv()->as_register(); assert_different_registers(mdo, recv); diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index a64ceb2a2ed..918a413adee 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -383,6 +383,7 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp //------------------------------------------------------------------------------ // frame::adjust_unextended_sp +#ifdef ASSERT void frame::adjust_unextended_sp() { // On x86, sites calling method handle intrinsics and lambda forms are treated // as any other call site. Therefore, no special action is needed when we are @@ -394,11 +395,12 @@ void frame::adjust_unextended_sp() { // If the sender PC is a deoptimization point, get the original PC. if (sender_cm->is_deopt_entry(_pc) || sender_cm->is_deopt_mh_entry(_pc)) { - DEBUG_ONLY(verify_deopt_original_pc(sender_cm, _unextended_sp)); + verify_deopt_original_pc(sender_cm, _unextended_sp); } } } } +#endif //------------------------------------------------------------------------------ // frame::update_map_with_saved_link diff --git a/src/hotspot/cpu/x86/frame_x86.hpp b/src/hotspot/cpu/x86/frame_x86.hpp index dbfcaf70dc3..db8d5dc71ea 100644 --- a/src/hotspot/cpu/x86/frame_x86.hpp +++ b/src/hotspot/cpu/x86/frame_x86.hpp @@ -117,7 +117,7 @@ // original sp we use that convention. intptr_t* _unextended_sp; - void adjust_unextended_sp(); + void adjust_unextended_sp() NOT_DEBUG_RETURN; intptr_t* ptr_at_addr(int offset) const { return (intptr_t*) addr_at(offset); diff --git a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp index 681dcc8a56b..54583b154c2 100644 --- a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp +++ b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp @@ -46,7 +46,7 @@ const bool CCallingConventionRequiresIntsAsLongs = false; // pure C1, 32-bit, small machine // i486 was the last Intel chip with 16-byte cache line size #define DEFAULT_CACHE_LINE_SIZE 32 -#elif defined(COMPILER2) || defined(SHARK) +#elif defined(COMPILER2) #ifdef _LP64 // pure C2, 64-bit, large machine #define DEFAULT_CACHE_LINE_SIZE 128 diff --git a/src/hotspot/cpu/x86/jniTypes_x86.hpp b/src/hotspot/cpu/x86/jniTypes_x86.hpp index 170cd6e3adc..ad888dbf059 100644 --- a/src/hotspot/cpu/x86/jniTypes_x86.hpp +++ b/src/hotspot/cpu/x86/jniTypes_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, 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 @@ -25,9 +25,9 @@ #ifndef CPU_X86_VM_JNITYPES_X86_HPP #define CPU_X86_VM_JNITYPES_X86_HPP +#include "jni.h" #include "memory/allocation.hpp" #include "oops/oop.hpp" -#include "prims/jni.h" // This file holds platform-dependent routines used to write primitive jni // types to the array of arguments passed into JavaCalls::call diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index a8a908344e1..e2be5a3a6a4 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -2783,6 +2783,21 @@ void MacroAssembler::cmpptr(Address src1, AddressLiteral src2) { #endif // _LP64 } +void MacroAssembler::cmpoop(Register src1, Register src2) { + cmpptr(src1, src2); +} + +void MacroAssembler::cmpoop(Register src1, Address src2) { + cmpptr(src1, src2); +} + +#ifdef _LP64 +void MacroAssembler::cmpoop(Register src1, jobject src2) { + movoop(rscratch1, src2); + cmpptr(src1, rscratch1); +} +#endif + void MacroAssembler::locked_cmpxchgptr(Register reg, AddressLiteral adr) { if (reachable(adr)) { if (os::is_MP()) @@ -6617,6 +6632,7 @@ void MacroAssembler::load_mirror(Register mirror, Register method) { movptr(mirror, Address(mirror, ConstMethod::constants_offset())); movptr(mirror, Address(mirror, ConstantPool::pool_holder_offset_in_bytes())); movptr(mirror, Address(mirror, mirror_offset)); + resolve_oop_handle(mirror); } void MacroAssembler::load_klass(Register dst, Register src) { @@ -8398,7 +8414,7 @@ void MacroAssembler::arrays_equals(bool is_array_equ, Register ary1, Register ar if (is_array_equ) { // Check the input args - cmpptr(ary1, ary2); + cmpoop(ary1, ary2); jcc(Assembler::equal, TRUE_LABEL); // Need additional checks for arrays_equals. diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 9fa0bdbcd65..fe6ca1e467f 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -750,9 +750,12 @@ class MacroAssembler: public Assembler { void cmpklass(Address dst, Metadata* obj); void cmpklass(Register dst, Metadata* obj); void cmpoop(Address dst, jobject obj); - void cmpoop(Register dst, jobject obj); #endif // _LP64 + void cmpoop(Register src1, Register src2); + void cmpoop(Register src1, Address src2); + void cmpoop(Register dst, jobject obj); + // NOTE src2 must be the lval. This is NOT an mem-mem compare void cmpptr(Address src1, AddressLiteral src2); diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index 2dc5660e9d9..81d57ed3422 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -182,7 +182,7 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, sizeof(u2), /*is_signed*/ false); // assert(sizeof(u2) == sizeof(Method::_size_of_parameters), ""); Label L; - __ cmpptr(recv, __ argument_address(temp2, -1)); + __ cmpoop(recv, __ argument_address(temp2, -1)); __ jcc(Assembler::equal, L); __ movptr(rax, __ argument_address(temp2, -1)); __ STOP("receiver not on stack"); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index bbe81875e91..fd8ee726abd 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -566,7 +566,7 @@ class StubGenerator: public StubCodeGenerator { return start; } - // Support for intptr_t atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) + // Support for intptr_t atomic::xchg_long(jlong exchange_value, volatile jlong* dest) // // Arguments : // c_rarg0: exchange_value @@ -574,8 +574,8 @@ class StubGenerator: public StubCodeGenerator { // // Result: // *dest <- ex, return (orig *dest) - address generate_atomic_xchg_ptr() { - StubCodeMark mark(this, "StubRoutines", "atomic_xchg_ptr"); + address generate_atomic_xchg_long() { + StubCodeMark mark(this, "StubRoutines", "atomic_xchg_long"); address start = __ pc(); __ movptr(rax, c_rarg0); // Copy to eax we need a return value anyhow @@ -4998,7 +4998,7 @@ class StubGenerator: public StubCodeGenerator { // atomic calls StubRoutines::_atomic_xchg_entry = generate_atomic_xchg(); - StubRoutines::_atomic_xchg_ptr_entry = generate_atomic_xchg_ptr(); + StubRoutines::_atomic_xchg_long_entry = generate_atomic_xchg_long(); StubRoutines::_atomic_cmpxchg_entry = generate_atomic_cmpxchg(); StubRoutines::_atomic_cmpxchg_byte_entry = generate_atomic_cmpxchg_byte(); StubRoutines::_atomic_cmpxchg_long_entry = generate_atomic_cmpxchg_long(); diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index 60335333076..e3c2d878344 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -2315,7 +2315,7 @@ void TemplateTable::if_acmp(Condition cc) { // assume branch is more often taken than not (loops use backward branches) Label not_taken; __ pop_ptr(rdx); - __ cmpptr(rdx, rax); + __ cmpoop(rdx, rax); __ jcc(j_not(cc), not_taken); branch(false, false); __ bind(not_taken); @@ -2563,6 +2563,13 @@ void TemplateTable::_return(TosState state) { __ bind(skip_register_finalizer); } + // Explicitly reset last_sp, for handling special case in TemplateInterpreter::deopt_reexecute_entry +#ifdef ASSERT + if (state == vtos) { + __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); + } +#endif + // Narrow result if state is itos but result type is smaller. // Need to narrow in the return bytecode rather than in generate_return_entry // since compiled code callers expect the result to already be narrowed. @@ -2665,6 +2672,7 @@ void TemplateTable::load_field_cp_cache_entry(Register obj, ConstantPoolCacheEntry::f1_offset()))); const int mirror_offset = in_bytes(Klass::java_mirror_offset()); __ movptr(obj, Address(obj, mirror_offset)); + __ resolve_oop_handle(obj); } } diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 99e402f8dee..6e3acc22315 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -46,7 +46,7 @@ address VM_Version::_cpuinfo_segv_addr = 0; address VM_Version::_cpuinfo_cont_addr = 0; static BufferBlob* stub_blob; -static const int stub_size = 1000; +static const int stub_size = 1100; extern "C" { typedef void (*get_cpu_info_stub_t)(void*); @@ -70,7 +70,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator { bool use_evex = FLAG_IS_DEFAULT(UseAVX) || (UseAVX > 2); Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4; - Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, done, wrapup; + Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, ext_cpuid8, done, wrapup; Label legacy_setup, save_restore_except, legacy_save_restore, start_simd_check; StubCodeMark mark(this, "VM_Version", "get_cpu_info_stub"); @@ -267,14 +267,30 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ cmpl(rax, 0x80000000); // Is cpuid(0x80000001) supported? __ jcc(Assembler::belowEqual, done); __ cmpl(rax, 0x80000004); // Is cpuid(0x80000005) supported? - __ jccb(Assembler::belowEqual, ext_cpuid1); + __ jcc(Assembler::belowEqual, ext_cpuid1); __ cmpl(rax, 0x80000006); // Is cpuid(0x80000007) supported? __ jccb(Assembler::belowEqual, ext_cpuid5); __ cmpl(rax, 0x80000007); // Is cpuid(0x80000008) supported? __ jccb(Assembler::belowEqual, ext_cpuid7); + __ cmpl(rax, 0x80000008); // Is cpuid(0x80000009 and above) supported? + __ jccb(Assembler::belowEqual, ext_cpuid8); + __ cmpl(rax, 0x8000001E); // Is cpuid(0x8000001E) supported? + __ jccb(Assembler::below, ext_cpuid8); + // + // Extended cpuid(0x8000001E) + // + __ movl(rax, 0x8000001E); + __ cpuid(); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid1E_offset()))); + __ movl(Address(rsi, 0), rax); + __ movl(Address(rsi, 4), rbx); + __ movl(Address(rsi, 8), rcx); + __ movl(Address(rsi,12), rdx); + // // Extended cpuid(0x80000008) // + __ bind(ext_cpuid8); __ movl(rax, 0x80000008); __ cpuid(); __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid8_offset()))); @@ -1109,11 +1125,27 @@ void VM_Version::get_processor_features() { } #ifdef COMPILER2 - if (MaxVectorSize > 16) { - // Limit vectors size to 16 bytes on current AMD cpus. + if (cpu_family() < 0x17 && MaxVectorSize > 16) { + // Limit vectors size to 16 bytes on AMD cpus < 17h. FLAG_SET_DEFAULT(MaxVectorSize, 16); } #endif // COMPILER2 + + // Some defaults for AMD family 17h + if ( cpu_family() == 0x17 ) { + // On family 17h processors use XMM and UnalignedLoadStores for Array Copy + if (supports_sse2() && FLAG_IS_DEFAULT(UseXMMForArrayCopy)) { + FLAG_SET_DEFAULT(UseXMMForArrayCopy, true); + } + if (supports_sse2() && FLAG_IS_DEFAULT(UseUnalignedLoadStores)) { + FLAG_SET_DEFAULT(UseUnalignedLoadStores, true); + } +#ifdef COMPILER2 + if (supports_sse4_2() && FLAG_IS_DEFAULT(UseFPUForSpilling)) { + FLAG_SET_DEFAULT(UseFPUForSpilling, true); + } +#endif + } } if( is_intel() ) { // Intel cpus specific settings diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index 23c2c7c195c..0a3b53a5271 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -228,6 +228,15 @@ class VM_Version : public Abstract_VM_Version { } bits; }; + union ExtCpuid1EEbx { + uint32_t value; + struct { + uint32_t : 8, + threads_per_core : 8, + : 16; + } bits; + }; + union XemXcr0Eax { uint32_t value; struct { @@ -398,6 +407,12 @@ protected: ExtCpuid8Ecx ext_cpuid8_ecx; uint32_t ext_cpuid8_edx; // reserved + // cpuid function 0x8000001E // AMD 17h + uint32_t ext_cpuid1E_eax; + ExtCpuid1EEbx ext_cpuid1E_ebx; // threads per core (AMD17h) + uint32_t ext_cpuid1E_ecx; + uint32_t ext_cpuid1E_edx; // unused currently + // extended control register XCR0 (the XFEATURE_ENABLED_MASK register) XemXcr0Eax xem_xcr0_eax; uint32_t xem_xcr0_edx; // reserved @@ -505,6 +520,14 @@ protected: result |= CPU_CLMUL; if (_cpuid_info.sef_cpuid7_ebx.bits.rtm != 0) result |= CPU_RTM; + if(_cpuid_info.sef_cpuid7_ebx.bits.adx != 0) + result |= CPU_ADX; + if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0) + result |= CPU_BMI2; + if (_cpuid_info.sef_cpuid7_ebx.bits.sha != 0) + result |= CPU_SHA; + if (_cpuid_info.std_cpuid1_ecx.bits.fma != 0) + result |= CPU_FMA; // AMD features. if (is_amd()) { @@ -518,16 +541,8 @@ protected: } // Intel features. if(is_intel()) { - if(_cpuid_info.sef_cpuid7_ebx.bits.adx != 0) - result |= CPU_ADX; - if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0) - result |= CPU_BMI2; - if (_cpuid_info.sef_cpuid7_ebx.bits.sha != 0) - result |= CPU_SHA; if(_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0) result |= CPU_LZCNT; - if (_cpuid_info.std_cpuid1_ecx.bits.fma != 0) - result |= CPU_FMA; // for Intel, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw if (_cpuid_info.ext_cpuid1_ecx.bits.misalignsse != 0) { result |= CPU_3DNOW_PREFETCH; @@ -590,6 +605,7 @@ public: static ByteSize ext_cpuid5_offset() { return byte_offset_of(CpuidInfo, ext_cpuid5_eax); } static ByteSize ext_cpuid7_offset() { return byte_offset_of(CpuidInfo, ext_cpuid7_eax); } static ByteSize ext_cpuid8_offset() { return byte_offset_of(CpuidInfo, ext_cpuid8_eax); } + static ByteSize ext_cpuid1E_offset() { return byte_offset_of(CpuidInfo, ext_cpuid1E_eax); } static ByteSize tpl_cpuidB0_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB0_eax); } static ByteSize tpl_cpuidB1_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB1_eax); } static ByteSize tpl_cpuidB2_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB2_eax); } @@ -673,8 +689,12 @@ public: if (is_intel() && supports_processor_topology()) { result = _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus; } else if (_cpuid_info.std_cpuid1_edx.bits.ht != 0) { - result = _cpuid_info.std_cpuid1_ebx.bits.threads_per_cpu / - cores_per_cpu(); + if (cpu_family() >= 0x17) { + result = _cpuid_info.ext_cpuid1E_ebx.bits.threads_per_core + 1; + } else { + result = _cpuid_info.std_cpuid1_ebx.bits.threads_per_cpu / + cores_per_cpu(); + } } return (result == 0 ? 1 : result); } diff --git a/src/hotspot/cpu/zero/cppInterpreter_zero.cpp b/src/hotspot/cpu/zero/cppInterpreter_zero.cpp index 5c5a12a7085..4d6a9425395 100644 --- a/src/hotspot/cpu/zero/cppInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/cppInterpreter_zero.cpp @@ -50,9 +50,6 @@ #include "stack_zero.inline.hpp" #include "utilities/debug.hpp" #include "utilities/macros.hpp" -#ifdef SHARK -#include "shark/shark_globals.hpp" -#endif #ifdef CC_INTERP @@ -276,7 +273,7 @@ int CppInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { markOop disp = lockee->mark()->set_unlocked(); monitor->lock()->set_displaced_header(disp); - if (Atomic::cmpxchg_ptr(monitor, lockee->mark_addr(), disp) != disp) { + if (Atomic::cmpxchg((markOop)monitor, lockee->mark_addr(), disp) != disp) { if (thread->is_lock_owned((address) disp->clear_lock_bits())) { monitor->lock()->set_displaced_header(NULL); } @@ -420,7 +417,8 @@ int CppInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { monitor->set_obj(NULL); if (header != NULL) { - if (Atomic::cmpxchg_ptr(header, rcvr->mark_addr(), lock) != lock) { + markOop old_header = markOopDesc::encode(lock); + if (rcvr->cas_set_mark(header, old_header) != old_header) { monitor->set_obj(rcvr); { HandleMark hm(thread); CALL_VM_NOCHECK(InterpreterRuntime::monitorexit(thread, monitor)); diff --git a/src/hotspot/cpu/zero/frame_zero.cpp b/src/hotspot/cpu/zero/frame_zero.cpp index ad4887fb4d6..24a1ea99eb4 100644 --- a/src/hotspot/cpu/zero/frame_zero.cpp +++ b/src/hotspot/cpu/zero/frame_zero.cpp @@ -71,7 +71,6 @@ frame frame::sender_for_entry_frame(RegisterMap *map) const { frame frame::sender_for_nonentry_frame(RegisterMap *map) const { assert(zeroframe()->is_interpreter_frame() || - zeroframe()->is_shark_frame() || zeroframe()->is_fake_stub_frame(), "wrong type of frame"); return frame(zeroframe()->next(), sender_sp()); } @@ -101,8 +100,6 @@ void frame::patch_pc(Thread* thread, address pc) { if (pc != NULL) { _cb = CodeCache::find_blob(pc); - SharkFrame* sharkframe = zeroframe()->as_shark_frame(); - sharkframe->set_pc(pc); _pc = pc; _deopt_state = is_deoptimized; @@ -233,8 +230,6 @@ void ZeroFrame::identify_word(int frame_index, strncpy(valuebuf, "ENTRY_FRAME", buflen); else if (is_interpreter_frame()) strncpy(valuebuf, "INTERPRETER_FRAME", buflen); - else if (is_shark_frame()) - strncpy(valuebuf, "SHARK_FRAME", buflen); else if (is_fake_stub_frame()) strncpy(valuebuf, "FAKE_STUB_FRAME", buflen); break; @@ -248,10 +243,6 @@ void ZeroFrame::identify_word(int frame_index, as_interpreter_frame()->identify_word( frame_index, offset, fieldbuf, valuebuf, buflen); } - else if (is_shark_frame()) { - as_shark_frame()->identify_word( - frame_index, offset, fieldbuf, valuebuf, buflen); - } else if (is_fake_stub_frame()) { as_fake_stub_frame()->identify_word( frame_index, offset, fieldbuf, valuebuf, buflen); @@ -350,50 +341,6 @@ void InterpreterFrame::identify_word(int frame_index, fieldbuf, buflen); } -void SharkFrame::identify_word(int frame_index, - int offset, - char* fieldbuf, - char* valuebuf, - int buflen) const { - // Fixed part - switch (offset) { - case pc_off: - strncpy(fieldbuf, "pc", buflen); - if (method()->is_method()) { - CompiledMethod *code = method()->code(); - if (code && code->pc_desc_at(pc())) { - SimpleScopeDesc ssd(code, pc()); - snprintf(valuebuf, buflen, PTR_FORMAT " (bci %d)", - (intptr_t) pc(), ssd.bci()); - } - } - return; - - case unextended_sp_off: - strncpy(fieldbuf, "unextended_sp", buflen); - return; - - case method_off: - strncpy(fieldbuf, "method", buflen); - if (method()->is_method()) { - method()->name_and_sig_as_C_string(valuebuf, buflen); - } - return; - - case oop_tmp_off: - strncpy(fieldbuf, "oop_tmp", buflen); - return; - } - - // Variable part - if (method()->is_method()) { - identify_vp_word(frame_index, addr_of_word(offset), - addr_of_word(header_words + 1), - unextended_sp() + method()->max_stack(), - fieldbuf, buflen); - } -} - void ZeroFrame::identify_vp_word(int frame_index, intptr_t* addr, intptr_t* monitor_base, diff --git a/src/hotspot/cpu/zero/frame_zero.hpp b/src/hotspot/cpu/zero/frame_zero.hpp index 2f1c931c690..23773c12db0 100644 --- a/src/hotspot/cpu/zero/frame_zero.hpp +++ b/src/hotspot/cpu/zero/frame_zero.hpp @@ -62,9 +62,6 @@ const InterpreterFrame *zero_interpreterframe() const { return zeroframe()->as_interpreter_frame(); } - const SharkFrame *zero_sharkframe() const { - return zeroframe()->as_shark_frame(); - } public: bool is_fake_stub_frame() const; diff --git a/src/hotspot/cpu/zero/frame_zero.inline.hpp b/src/hotspot/cpu/zero/frame_zero.inline.hpp index 1ecd9db38a8..498840724b7 100644 --- a/src/hotspot/cpu/zero/frame_zero.inline.hpp +++ b/src/hotspot/cpu/zero/frame_zero.inline.hpp @@ -56,18 +56,6 @@ inline frame::frame(ZeroFrame* zf, intptr_t* sp) { _deopt_state = not_deoptimized; break; - case ZeroFrame::SHARK_FRAME: { - _pc = zero_sharkframe()->pc(); - _cb = CodeCache::find_blob_unsafe(pc()); - address original_pc = CompiledMethod::get_deopt_original_pc(this); - if (original_pc != NULL) { - _pc = original_pc; - _deopt_state = is_deoptimized; - } else { - _deopt_state = not_deoptimized; - } - break; - } case ZeroFrame::FAKE_STUB_FRAME: _pc = NULL; _cb = NULL; @@ -177,10 +165,7 @@ inline intptr_t* frame::entry_frame_argument_at(int offset) const { } inline intptr_t* frame::unextended_sp() const { - if (zeroframe()->is_shark_frame()) - return zero_sharkframe()->unextended_sp(); - else - return (intptr_t *) -1; + return (intptr_t *) -1; } #endif // CPU_ZERO_VM_FRAME_ZERO_INLINE_HPP diff --git a/src/hotspot/cpu/zero/icache_zero.hpp b/src/hotspot/cpu/zero/icache_zero.hpp index 2383d211e2e..eefe552f78d 100644 --- a/src/hotspot/cpu/zero/icache_zero.hpp +++ b/src/hotspot/cpu/zero/icache_zero.hpp @@ -29,7 +29,7 @@ // Interface for updating the instruction cache. Whenever the VM // modifies code, part of the processor instruction cache potentially // has to be flushed. This implementation is empty: Zero never deals -// with code, and LLVM handles cache flushing for Shark. +// with code. class ICache : public AbstractICache { public: diff --git a/src/hotspot/cpu/zero/jniTypes_zero.hpp b/src/hotspot/cpu/zero/jniTypes_zero.hpp index 766b5e1d6bc..ae464c77aae 100644 --- a/src/hotspot/cpu/zero/jniTypes_zero.hpp +++ b/src/hotspot/cpu/zero/jniTypes_zero.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, 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 @@ -25,9 +25,9 @@ #ifndef CPU_ZERO_VM_JNITYPES_ZERO_HPP #define CPU_ZERO_VM_JNITYPES_ZERO_HPP +#include "jni.h" #include "memory/allocation.hpp" #include "oops/oop.hpp" -#include "prims/jni.h" // This file holds platform-dependent routines used to write primitive jni // types to the array of arguments passed into JavaCalls::call diff --git a/src/hotspot/cpu/zero/nativeInst_zero.cpp b/src/hotspot/cpu/zero/nativeInst_zero.cpp index 144683f2b4f..c60caa507c7 100644 --- a/src/hotspot/cpu/zero/nativeInst_zero.cpp +++ b/src/hotspot/cpu/zero/nativeInst_zero.cpp @@ -42,11 +42,6 @@ // insert a jump to SharedRuntime::get_handle_wrong_method_stub() // (dest) at the start of a compiled method (verified_entry) to avoid // a race where a method is invoked while being made non-entrant. -// -// In Shark, verified_entry is a pointer to a SharkEntry. We can -// handle this simply by changing it's entry point to point at the -// interpreter. This only works because the interpreter and Shark -// calling conventions are the same. void NativeJump::patch_verified_entry(address entry, address verified_entry, diff --git a/src/hotspot/cpu/zero/relocInfo_zero.cpp b/src/hotspot/cpu/zero/relocInfo_zero.cpp index 82fa13da684..8482e53d37b 100644 --- a/src/hotspot/cpu/zero/relocInfo_zero.cpp +++ b/src/hotspot/cpu/zero/relocInfo_zero.cpp @@ -50,7 +50,7 @@ address Relocation::pd_get_address_from_code() { } address* Relocation::pd_address_in_code() { - // Relocations in Shark are just stored directly + ShouldNotCallThis(); return (address *) addr(); } diff --git a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp index 27b96b57bec..e9916c429b1 100644 --- a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp +++ b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp @@ -41,11 +41,6 @@ #ifdef COMPILER2 #include "opto/runtime.hpp" #endif -#ifdef SHARK -#include "compiler/compileBroker.hpp" -#include "shark/sharkCompiler.hpp" -#endif - static address zero_null_code_stub() { @@ -80,16 +75,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, BasicType *sig_bt, VMRegPair *regs, BasicType ret_type) { -#ifdef SHARK - return SharkCompiler::compiler()->generate_native_wrapper(masm, - method, - compile_id, - sig_bt, - ret_type); -#else ShouldNotCallThis(); return NULL; -#endif // SHARK } int Deoptimization::last_frame_adjust(int callee_parameters, diff --git a/src/hotspot/cpu/zero/sharkFrame_zero.hpp b/src/hotspot/cpu/zero/sharkFrame_zero.hpp deleted file mode 100644 index ff26fbccf86..00000000000 --- a/src/hotspot/cpu/zero/sharkFrame_zero.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef CPU_ZERO_VM_SHARKFRAME_ZERO_HPP -#define CPU_ZERO_VM_SHARKFRAME_ZERO_HPP - -#include "oops/method.hpp" -#include "stack_zero.hpp" - -// | ... | -// +--------------------+ ------------------ -// | stack slot n-1 | low addresses -// | ... | -// | stack slot 0 | -// | monitor m-1 | -// | ... | -// | monitor 0 | -// | oop_tmp | -// | method | -// | unextended_sp | -// | pc | -// | frame_type | -// | next_frame | high addresses -// +--------------------+ ------------------ -// | ... | - -class SharkFrame : public ZeroFrame { - friend class SharkStack; - - private: - SharkFrame() : ZeroFrame() { - ShouldNotCallThis(); - } - - protected: - enum Layout { - pc_off = jf_header_words, - unextended_sp_off, - method_off, - oop_tmp_off, - header_words - }; - - public: - address pc() const { - return (address) value_of_word(pc_off); - } - - void set_pc(address pc) const { - *((address*) addr_of_word(pc_off)) = pc; - } - - intptr_t* unextended_sp() const { - return (intptr_t *) value_of_word(unextended_sp_off); - } - - Method* method() const { - return (Method*) value_of_word(method_off); - } - - public: - void identify_word(int frame_index, - int offset, - char* fieldbuf, - char* valuebuf, - int buflen) const; -}; - -#endif // CPU_ZERO_VM_SHARKFRAME_ZERO_HPP diff --git a/src/hotspot/cpu/zero/shark_globals_zero.hpp b/src/hotspot/cpu/zero/shark_globals_zero.hpp deleted file mode 100644 index 9d478114520..00000000000 --- a/src/hotspot/cpu/zero/shark_globals_zero.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010 Red Hat, Inc. - * 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. - * - */ - -#ifndef CPU_ZERO_VM_SHARK_GLOBALS_ZERO_HPP -#define CPU_ZERO_VM_SHARK_GLOBALS_ZERO_HPP - -// Set the default values for platform dependent flags used by the -// Shark compiler. See globals.hpp for details of what they do. - -define_pd_global(bool, BackgroundCompilation, true ); -define_pd_global(bool, UseTLAB, true ); -define_pd_global(bool, ResizeTLAB, true ); -define_pd_global(bool, InlineIntrinsics, false); -define_pd_global(bool, PreferInterpreterNativeStubs, false); -define_pd_global(bool, ProfileTraps, false); -define_pd_global(bool, UseOnStackReplacement, true ); -define_pd_global(bool, TieredCompilation, false); - -define_pd_global(intx, CompileThreshold, 1500); -define_pd_global(intx, Tier2CompileThreshold, 1500); -define_pd_global(intx, Tier3CompileThreshold, 2500); -define_pd_global(intx, Tier4CompileThreshold, 4500); - -define_pd_global(intx, Tier2BackEdgeThreshold, 100000); -define_pd_global(intx, Tier3BackEdgeThreshold, 100000); -define_pd_global(intx, Tier4BackEdgeThreshold, 100000); - -define_pd_global(intx, OnStackReplacePercentage, 933 ); -define_pd_global(intx, FreqInlineSize, 325 ); -define_pd_global(uintx, NewRatio, 12 ); -define_pd_global(size_t, NewSizeThreadIncrease, 4*K ); -define_pd_global(intx, InitialCodeCacheSize, 160*K); -define_pd_global(intx, ReservedCodeCacheSize, 32*M ); -define_pd_global(intx, NonProfiledCodeHeapSize, 13*M ); -define_pd_global(intx, ProfiledCodeHeapSize, 14*M ); -define_pd_global(intx, NonNMethodCodeHeapSize, 5*M ); -define_pd_global(bool, ProfileInterpreter, false); -define_pd_global(intx, CodeCacheExpansionSize, 32*K ); -define_pd_global(uintx, CodeCacheMinBlockLength, 1 ); -define_pd_global(uintx, CodeCacheMinimumUseSpace, 200*K); - -define_pd_global(size_t, MetaspaceSize, 12*M ); -define_pd_global(bool, NeverActAsServerClassMachine, true ); -define_pd_global(uint64_t, MaxRAM, 1ULL*G); -define_pd_global(bool, CICompileOSR, true ); - -#endif // CPU_ZERO_VM_SHARK_GLOBALS_ZERO_HPP diff --git a/src/hotspot/cpu/zero/stack_zero.cpp b/src/hotspot/cpu/zero/stack_zero.cpp index a9bf5309921..924f21c302b 100644 --- a/src/hotspot/cpu/zero/stack_zero.cpp +++ b/src/hotspot/cpu/zero/stack_zero.cpp @@ -52,9 +52,6 @@ void ZeroStack::handle_overflow(TRAPS) { intptr_t *sp = thread->zero_stack()->sp(); ZeroFrame *frame = thread->top_zero_frame(); while (frame) { - if (frame->is_shark_frame()) - break; - if (frame->is_interpreter_frame()) { interpreterState istate = frame->as_interpreter_frame()->interpreter_state(); diff --git a/src/hotspot/cpu/zero/stack_zero.hpp b/src/hotspot/cpu/zero/stack_zero.hpp index ca95c55a2b6..b610f45ac32 100644 --- a/src/hotspot/cpu/zero/stack_zero.hpp +++ b/src/hotspot/cpu/zero/stack_zero.hpp @@ -121,7 +121,6 @@ class ZeroStack { class EntryFrame; class InterpreterFrame; -class SharkFrame; class FakeStubFrame; // @@ -151,7 +150,6 @@ class ZeroFrame { enum FrameType { ENTRY_FRAME = 1, INTERPRETER_FRAME, - SHARK_FRAME, FAKE_STUB_FRAME }; @@ -180,9 +178,6 @@ class ZeroFrame { bool is_interpreter_frame() const { return type() == INTERPRETER_FRAME; } - bool is_shark_frame() const { - return type() == SHARK_FRAME; - } bool is_fake_stub_frame() const { return type() == FAKE_STUB_FRAME; } @@ -196,10 +191,6 @@ class ZeroFrame { assert(is_interpreter_frame(), "should be"); return (InterpreterFrame *) this; } - SharkFrame *as_shark_frame() const { - assert(is_shark_frame(), "should be"); - return (SharkFrame *) this; - } FakeStubFrame *as_fake_stub_frame() const { assert(is_fake_stub_frame(), "should be"); return (FakeStubFrame *) this; diff --git a/src/hotspot/cpu/zero/stack_zero.inline.hpp b/src/hotspot/cpu/zero/stack_zero.inline.hpp index 02d12e8e96d..3398df72486 100644 --- a/src/hotspot/cpu/zero/stack_zero.inline.hpp +++ b/src/hotspot/cpu/zero/stack_zero.inline.hpp @@ -29,7 +29,6 @@ #include "runtime/thread.hpp" #include "stack_zero.hpp" -// This function should match SharkStack::CreateStackOverflowCheck inline void ZeroStack::overflow_check(int required_words, TRAPS) { // Check the Zero stack if (available_words() < required_words) { diff --git a/src/hotspot/cpu/zero/stubGenerator_zero.cpp b/src/hotspot/cpu/zero/stubGenerator_zero.cpp index 9d64fb99e94..748ad405293 100644 --- a/src/hotspot/cpu/zero/stubGenerator_zero.cpp +++ b/src/hotspot/cpu/zero/stubGenerator_zero.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2010, 2015 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -253,9 +253,8 @@ class StubGenerator: public StubCodeGenerator { // atomic calls StubRoutines::_atomic_xchg_entry = ShouldNotCallThisStub(); - StubRoutines::_atomic_xchg_ptr_entry = ShouldNotCallThisStub(); + StubRoutines::_atomic_xchg_long_entry = ShouldNotCallThisStub(); StubRoutines::_atomic_cmpxchg_entry = ShouldNotCallThisStub(); - StubRoutines::_atomic_cmpxchg_ptr_entry = ShouldNotCallThisStub(); StubRoutines::_atomic_cmpxchg_byte_entry = ShouldNotCallThisStub(); StubRoutines::_atomic_cmpxchg_long_entry = ShouldNotCallThisStub(); StubRoutines::_atomic_add_entry = ShouldNotCallThisStub(); diff --git a/src/hotspot/os/aix/decoder_aix.hpp b/src/hotspot/os/aix/decoder_aix.hpp index 50b26b5193d..0389852e4cb 100644 --- a/src/hotspot/os/aix/decoder_aix.hpp +++ b/src/hotspot/os/aix/decoder_aix.hpp @@ -34,8 +34,6 @@ class AIXDecoder: public AbstractDecoder { } virtual ~AIXDecoder() {} - virtual bool can_decode_C_frame_in_vm() const { return true; } - virtual bool demangle(const char* symbol, char* buf, int buflen) { return false; } // use AixSymbols::get_function_name to demangle virtual bool decode(address addr, char* buf, int buflen, int* offset, const char* modulepath, bool demangle) { diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 68a206afd14..eaf7a4f2ae9 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -770,8 +770,15 @@ static void *thread_native_entry(Thread *thread) { const pthread_t pthread_id = ::pthread_self(); const tid_t kernel_thread_id = ::thread_self(); - log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", kernel thread id: " UINTX_FORMAT ").", - os::current_thread_id(), (uintx) kernel_thread_id); + LogTarget(Info, os, thread) lt; + if (lt.is_enabled()) { + address low_address = thread->stack_end(); + address high_address = thread->stack_base(); + lt.print("Thread is alive (tid: " UINTX_FORMAT ", kernel thread id: " UINTX_FORMAT + ", stack [" PTR_FORMAT " - " PTR_FORMAT " (" SIZE_FORMAT "k using %uk pages)).", + os::current_thread_id(), (uintx) kernel_thread_id, low_address, high_address, + (high_address - low_address) / K, os::Aix::query_pagesize(low_address) / K); + } // Normally, pthread stacks on AIX live in the data segment (are allocated with malloc() // by the pthread library). In rare cases, this may not be the case, e.g. when third-party @@ -864,6 +871,14 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, // Calculate stack size if it's not specified by caller. size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size); + // JDK-8187028: It was observed that on some configurations (4K backed thread stacks) + // the real thread stack size may be smaller than the requested stack size, by as much as 64K. + // This very much looks like a pthread lib error. As a workaround, increase the stack size + // by 64K for small thread stacks (arbitrarily choosen to be < 4MB) + if (stack_size < 4096 * K) { + stack_size += 64 * K; + } + // On Aix, pthread_attr_setstacksize fails with huge values and leaves the // thread size in attr unchanged. If this is the minimal stack size as set // by pthread_attr_init this leads to crashes after thread creation. E.g. the @@ -874,8 +889,12 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, stack_size / K); } - // Configure libc guard page. - ret = pthread_attr_setguardsize(&attr, os::Aix::default_guard_size(thr_type)); + // Save some cycles and a page by disabling OS guard pages where we have our own + // VM guard pages (in java threads). For other threads, keep system default guard + // pages in place. + if (thr_type == java_thread || thr_type == compiler_thread) { + ret = pthread_attr_setguardsize(&attr, 0); + } pthread_t tid = 0; if (ret == 0) { @@ -3004,19 +3023,6 @@ bool os::Aix::chained_handler(int sig, siginfo_t* siginfo, void* context) { return chained; } -size_t os::Aix::default_guard_size(os::ThreadType thr_type) { - // Creating guard page is very expensive. Java thread has HotSpot - // guard pages, only enable glibc guard page for non-Java threads. - // (Remember: compiler thread is a Java thread, too!) - // - // Aix can have different page sizes for stack (4K) and heap (64K). - // As Hotspot knows only one page size, we assume the stack has - // the same page size as the heap. Returning page_size() here can - // cause 16 guard pages which we want to avoid. Thus we return 4K - // which will be rounded to the real page size by the OS. - return ((thr_type == java_thread || thr_type == compiler_thread) ? 0 : 4 * K); -} - struct sigaction* os::Aix::get_preinstalled_handler(int sig) { if (sigismember(&sigs, sig)) { return &sigact[sig]; @@ -3443,8 +3449,6 @@ void os::init(void) { init_random(1234567); - ThreadCritical::initialize(); - // Main_thread points to the aboriginal thread. Aix::_main_thread = pthread_self(); diff --git a/src/hotspot/os/aix/os_aix.hpp b/src/hotspot/os/aix/os_aix.hpp index 95a32704195..65bbe9186dc 100644 --- a/src/hotspot/os/aix/os_aix.hpp +++ b/src/hotspot/os/aix/os_aix.hpp @@ -139,9 +139,6 @@ class Aix { // libpthread version string static void libpthread_init(); - // Return default libc guard size for the specified thread type. - static size_t default_guard_size(os::ThreadType thr_type); - // Function returns true if we run on OS/400 (pase), false if we run // on AIX. static bool on_pase() { diff --git a/src/hotspot/os/aix/threadCritical_aix.cpp b/src/hotspot/os/aix/threadCritical_aix.cpp index a5d893ba9f1..cd25cb68dc4 100644 --- a/src/hotspot/os/aix/threadCritical_aix.cpp +++ b/src/hotspot/os/aix/threadCritical_aix.cpp @@ -38,12 +38,6 @@ static pthread_t tc_owner = 0; static pthread_mutex_t tc_mutex = PTHREAD_MUTEX_INITIALIZER; static int tc_count = 0; -void ThreadCritical::initialize() { -} - -void ThreadCritical::release() { -} - ThreadCritical::ThreadCritical() { pthread_t self = pthread_self(); if (self != tc_owner) { diff --git a/src/hotspot/os/bsd/decoder_machO.hpp b/src/hotspot/os/bsd/decoder_machO.hpp index 7872d6da5a9..d15dc738d34 100644 --- a/src/hotspot/os/bsd/decoder_machO.hpp +++ b/src/hotspot/os/bsd/decoder_machO.hpp @@ -35,9 +35,6 @@ class MachODecoder : public AbstractDecoder { public: MachODecoder() { } virtual ~MachODecoder() { } - virtual bool can_decode_C_frame_in_vm() const { - return true; - } virtual bool demangle(const char* symbol, char* buf, int buflen); virtual bool decode(address pc, char* buf, int buflen, int* offset, const void* base); diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index ef83bf31130..bfa7811f8da 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -3353,8 +3353,6 @@ void os::init(void) { init_random(1234567); - ThreadCritical::initialize(); - Bsd::set_page_size(getpagesize()); if (Bsd::page_size() == -1) { fatal("os_bsd.cpp: os::init: sysconf failed (%s)", os::strerror(errno)); diff --git a/src/hotspot/os/bsd/threadCritical_bsd.cpp b/src/hotspot/os/bsd/threadCritical_bsd.cpp index 7cac3ca228b..71c51df599d 100644 --- a/src/hotspot/os/bsd/threadCritical_bsd.cpp +++ b/src/hotspot/os/bsd/threadCritical_bsd.cpp @@ -37,12 +37,6 @@ static pthread_t tc_owner = 0; static pthread_mutex_t tc_mutex = PTHREAD_MUTEX_INITIALIZER; static int tc_count = 0; -void ThreadCritical::initialize() { -} - -void ThreadCritical::release() { -} - ThreadCritical::ThreadCritical() { pthread_t self = pthread_self(); if (self != tc_owner) { diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index e6ebec3e53e..5eabc870287 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4768,8 +4768,6 @@ void os::init(void) { init_random(1234567); - ThreadCritical::initialize(); - Linux::set_page_size(sysconf(_SC_PAGESIZE)); if (Linux::page_size() == -1) { fatal("os_linux.cpp: os::init: sysconf failed (%s)", diff --git a/src/hotspot/os/linux/os_linux.inline.hpp b/src/hotspot/os/linux/os_linux.inline.hpp index a665e4c69c6..cf00c6a4621 100644 --- a/src/hotspot/os/linux/os_linux.inline.hpp +++ b/src/hotspot/os/linux/os_linux.inline.hpp @@ -98,6 +98,11 @@ inline int os::ftruncate(int fd, jlong length) { inline struct dirent* os::readdir(DIR* dirp, dirent *dbuf) { +// readdir_r has been deprecated since glibc 2.24. +// See https://sourceware.org/bugzilla/show_bug.cgi?id=19056 for more details. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + dirent* p; int status; assert(dirp != NULL, "just checking"); @@ -111,6 +116,8 @@ inline struct dirent* os::readdir(DIR* dirp, dirent *dbuf) return NULL; } else return p; + +#pragma GCC diagnostic pop } inline int os::closedir(DIR *dirp) { diff --git a/src/hotspot/os/linux/threadCritical_linux.cpp b/src/hotspot/os/linux/threadCritical_linux.cpp index 7cac3ca228b..71c51df599d 100644 --- a/src/hotspot/os/linux/threadCritical_linux.cpp +++ b/src/hotspot/os/linux/threadCritical_linux.cpp @@ -37,12 +37,6 @@ static pthread_t tc_owner = 0; static pthread_mutex_t tc_mutex = PTHREAD_MUTEX_INITIALIZER; static int tc_count = 0; -void ThreadCritical::initialize() { -} - -void ThreadCritical::release() { -} - ThreadCritical::ThreadCritical() { pthread_t self = pthread_self(); if (self != tc_owner) { diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 554238313f8..422f7fcac3c 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1770,6 +1770,12 @@ int os::PlatformEvent::park(jlong millis) { if (v == 0) { // Do this the hard way by blocking ... struct timespec abst; + // We have to watch for overflow when converting millis to nanos, + // but if millis is that large then we will end up limiting to + // MAX_SECS anyway, so just do that here. + if (millis / MILLIUNITS > MAX_SECS) { + millis = jlong(MAX_SECS) * MILLIUNITS; + } to_abstime(&abst, millis * (NANOUNITS / MILLIUNITS), false); int ret = OS_TIMEOUT; diff --git a/src/hotspot/os/solaris/os_solaris.cpp b/src/hotspot/os/solaris/os_solaris.cpp index 065fcb4e602..814589d375d 100644 --- a/src/hotspot/os/solaris/os_solaris.cpp +++ b/src/hotspot/os/solaris/os_solaris.cpp @@ -4076,6 +4076,7 @@ int_fnP_cond_tP os::Solaris::_cond_broadcast; int_fnP_cond_tP_i_vP os::Solaris::_cond_init; int_fnP_cond_tP os::Solaris::_cond_destroy; int os::Solaris::_cond_scope = USYNC_THREAD; +bool os::Solaris::_synchronization_initialized; void os::Solaris::synchronization_init() { if (UseLWPSynchronization) { @@ -4125,6 +4126,7 @@ void os::Solaris::synchronization_init() { os::Solaris::set_cond_destroy(::cond_destroy); } } + _synchronization_initialized = true; } bool os::Solaris::liblgrp_init() { @@ -4198,9 +4200,6 @@ void os::init(void) { dladdr1_func = CAST_TO_FN_PTR(dladdr1_func_type, dlsym(hdl, "dladdr1")); } - // (Solaris only) this switches to calls that actually do locking. - ThreadCritical::initialize(); - main_thread = thr_self(); // dynamic lookup of functions that may not be available in our lowest diff --git a/src/hotspot/os/solaris/os_solaris.hpp b/src/hotspot/os/solaris/os_solaris.hpp index 56305846c58..c5fe31847f0 100644 --- a/src/hotspot/os/solaris/os_solaris.hpp +++ b/src/hotspot/os/solaris/os_solaris.hpp @@ -65,6 +65,8 @@ class Solaris { static int_fnP_cond_tP _cond_destroy; static int _cond_scope; + static bool _synchronization_initialized; + typedef uintptr_t lgrp_cookie_t; typedef id_t lgrp_id_t; typedef int lgrp_rsrc_t; @@ -227,6 +229,8 @@ class Solaris { static void set_cond_destroy(int_fnP_cond_tP func) { _cond_destroy = func; } static void set_cond_scope(int scope) { _cond_scope = scope; } + static bool synchronization_initialized() { return _synchronization_initialized; } + static void set_lgrp_home(lgrp_home_func_t func) { _lgrp_home = func; } static void set_lgrp_init(lgrp_init_func_t func) { _lgrp_init = func; } static void set_lgrp_fini(lgrp_fini_func_t func) { _lgrp_fini = func; } diff --git a/src/hotspot/os/solaris/threadCritical_solaris.cpp b/src/hotspot/os/solaris/threadCritical_solaris.cpp index 53bd865b592..bb2c9e7e875 100644 --- a/src/hotspot/os/solaris/threadCritical_solaris.cpp +++ b/src/hotspot/os/solaris/threadCritical_solaris.cpp @@ -42,10 +42,9 @@ static mutex_t global_mut; static thread_t global_mut_owner = -1; static int global_mut_count = 0; -static bool initialized = false; ThreadCritical::ThreadCritical() { - if (initialized) { + if (os::Solaris::synchronization_initialized()) { thread_t owner = thr_self(); if (global_mut_owner != owner) { if (os::Solaris::mutex_lock(&global_mut)) @@ -62,7 +61,7 @@ ThreadCritical::ThreadCritical() { } ThreadCritical::~ThreadCritical() { - if (initialized) { + if (os::Solaris::synchronization_initialized()) { assert(global_mut_owner == thr_self(), "must have correct owner"); assert(global_mut_count > 0, "must have correct count"); --global_mut_count; @@ -75,12 +74,3 @@ ThreadCritical::~ThreadCritical() { assert (Threads::number_of_threads() == 0, "valid only during initialization"); } } - -void ThreadCritical::initialize() { - // This method is called at the end of os::init(). Until - // then, we don't do real locking. - initialized = true; -} - -void ThreadCritical::release() { -} diff --git a/src/hotspot/os/windows/decoder_windows.cpp b/src/hotspot/os/windows/decoder_windows.cpp index 9e43367d494..ecb4c67934f 100644 --- a/src/hotspot/os/windows/decoder_windows.cpp +++ b/src/hotspot/os/windows/decoder_windows.cpp @@ -23,136 +23,28 @@ */ #include "precompiled.hpp" -#include "prims/jvm.h" -#include "runtime/arguments.hpp" -#include "runtime/os.hpp" -#include "decoder_windows.hpp" +#include "utilities/decoder.hpp" +#include "symbolengine.hpp" #include "windbghelp.hpp" -WindowsDecoder::WindowsDecoder() { - _can_decode_in_vm = true; - _decoder_status = no_error; - initialize(); +bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const char* modulepath, bool demangle) { + return SymbolEngine::decode(addr, buf, buflen, offset, demangle); } -void WindowsDecoder::initialize() { - if (!has_error()) { - HANDLE hProcess = ::GetCurrentProcess(); - WindowsDbgHelp::symSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS); - if (!WindowsDbgHelp::symInitialize(hProcess, NULL, TRUE)) { - _decoder_status = helper_init_error; - return; - } - - // set pdb search paths - char paths[MAX_PATH]; - int len = sizeof(paths); - if (!WindowsDbgHelp::symGetSearchPath(hProcess, paths, len)) { - paths[0] = '\0'; - } else { - // available spaces in path buffer - len -= (int)strlen(paths); - } - - char tmp_path[MAX_PATH]; - DWORD dwSize; - HMODULE hJVM = ::GetModuleHandle("jvm.dll"); - tmp_path[0] = '\0'; - // append the path where jvm.dll is located - if (hJVM != NULL && (dwSize = ::GetModuleFileName(hJVM, tmp_path, sizeof(tmp_path))) > 0) { - while (dwSize > 0 && tmp_path[dwSize] != '\\') { - dwSize --; - } - - tmp_path[dwSize] = '\0'; - - if (dwSize > 0 && len > (int)dwSize + 1) { - strncat(paths, os::path_separator(), 1); - strncat(paths, tmp_path, dwSize); - len -= dwSize + 1; - } - } - - // append $JRE/bin. Arguments::get_java_home actually returns $JRE - // path - char *p = Arguments::get_java_home(); - assert(p != NULL, "empty java home"); - size_t java_home_len = strlen(p); - if (len > (int)java_home_len + 5) { - strncat(paths, os::path_separator(), 1); - strncat(paths, p, java_home_len); - strncat(paths, "\\bin", 4); - len -= (int)(java_home_len + 5); - } - - // append $JDK/bin path if it exists - assert(java_home_len < MAX_PATH, "Invalid path length"); - // assume $JRE is under $JDK, construct $JDK/bin path and - // see if it exists or not - if (strncmp(&p[java_home_len - 3], "jre", 3) == 0) { - strncpy(tmp_path, p, java_home_len - 3); - tmp_path[java_home_len - 3] = '\0'; - strncat(tmp_path, "bin", 3); - - // if the directory exists - DWORD dwAttrib = GetFileAttributes(tmp_path); - if (dwAttrib != INVALID_FILE_ATTRIBUTES && - (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) { - // tmp_path should have the same length as java_home_len, since we only - // replaced 'jre' with 'bin' - if (len > (int)java_home_len + 1) { - strncat(paths, os::path_separator(), 1); - strncat(paths, tmp_path, java_home_len); - } - } - } - - WindowsDbgHelp::symSetSearchPath(hProcess, paths); - - // find out if jvm.dll contains private symbols, by decoding - // current function and comparing the result - address addr = (address)Decoder::demangle; - char buf[MAX_PATH]; - if (decode(addr, buf, sizeof(buf), NULL, NULL, true /* demangle */)) { - _can_decode_in_vm = !strcmp(buf, "Decoder::demangle"); - } - } +bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const void* base) { + return SymbolEngine::decode(addr, buf, buflen, offset, true); } -void WindowsDecoder::uninitialize() {} - -bool WindowsDecoder::can_decode_C_frame_in_vm() const { - return (!has_error() && _can_decode_in_vm); +bool Decoder::get_source_info(address pc, char* buf, size_t buflen, int* line) { + return SymbolEngine::get_source_info(pc, buf, buflen, line); } - -bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* modulepath, bool demangle_name) { - if (!has_error()) { - PIMAGEHLP_SYMBOL64 pSymbol; - char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)]; - pSymbol = (PIMAGEHLP_SYMBOL64)symbolInfo; - pSymbol->MaxNameLength = MAX_PATH; - pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - DWORD64 displacement; - if (WindowsDbgHelp::symGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) { - if (buf != NULL) { - if (!(demangle_name && demangle(pSymbol->Name, buf, buflen))) { - jio_snprintf(buf, buflen, "%s", pSymbol->Name); - } - } - if(offset != NULL) *offset = (int)displacement; - return true; - } - } - if (buf != NULL && buflen > 0) buf[0] = '\0'; - if (offset != NULL) *offset = -1; - return false; +bool Decoder::demangle(const char* symbol, char* buf, int buflen) { + return SymbolEngine::demangle(symbol, buf, buflen); } -bool WindowsDecoder::demangle(const char* symbol, char *buf, int buflen) { - if (!has_error()) { - return WindowsDbgHelp::unDecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE) > 0; - } - return false; +void Decoder::print_state_on(outputStream* st) { + WindowsDbgHelp::print_state_on(st); + SymbolEngine::print_state_on(st); } diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 5c464768eea..dedbc3f2e9b 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -74,6 +74,7 @@ #include "utilities/growableArray.hpp" #include "utilities/macros.hpp" #include "utilities/vmError.hpp" +#include "symbolengine.hpp" #include "windbghelp.hpp" @@ -134,6 +135,8 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) { if (ForceTimeHighResolution) { timeBeginPeriod(1L); } + WindowsDbgHelp::pre_initialize(); + SymbolEngine::pre_initialize(); break; case DLL_PROCESS_DETACH: if (ForceTimeHighResolution) { @@ -428,7 +431,7 @@ static unsigned __stdcall thread_native_entry(Thread* thread) { // When the VMThread gets here, the main thread may have already exited // which frees the CodeHeap containing the Atomic::add code if (thread != VMThread::vm_thread() && VMThread::vm_thread() != NULL) { - Atomic::dec_ptr((intptr_t*)&os::win32::_os_thread_count); + Atomic::dec(&os::win32::_os_thread_count); } // If a thread has not deleted itself ("delete this") as part of its @@ -634,7 +637,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, return NULL; } - Atomic::inc_ptr((intptr_t*)&os::win32::_os_thread_count); + Atomic::inc(&os::win32::_os_thread_count); // Store info on the Win32 thread into the OSThread osthread->set_thread_handle(thread_handle); @@ -1319,6 +1322,8 @@ static int _print_module(const char* fname, address base_address, void * os::dll_load(const char *name, char *ebuf, int ebuflen) { void * result = LoadLibrary(name); if (result != NULL) { + // Recalculate pdb search path if a DLL was loaded successfully. + SymbolEngine::recalc_search_path(); return result; } @@ -4032,6 +4037,8 @@ jint os::init_2(void) { return JNI_ERR; } + SymbolEngine::recalc_search_path(); + return JNI_OK; } diff --git a/src/hotspot/os/windows/symbolengine.cpp b/src/hotspot/os/windows/symbolengine.cpp new file mode 100644 index 00000000000..7f816dc365e --- /dev/null +++ b/src/hotspot/os/windows/symbolengine.cpp @@ -0,0 +1,641 @@ +/* + * Copyright (c) 2017, 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 "precompiled.hpp" +#include "utilities/globalDefinitions.hpp" +#include "symbolengine.hpp" +#include "utilities/debug.hpp" +#include "windbghelp.hpp" + +#include + +#include +#include + + + +// This code may be invoked normally but also as part of error reporting +// In the latter case, we may run under tight memory constraints (native oom) +// or in a stack overflow situation or the C heap may be corrupted. We may +// run very early before VM initialization or very late when C exit handlers +// run. In all these cases, callstacks would still be nice, so lets be robust. +// +// We need a number of buffers - for the pdb search path, module handle +// lists, for demangled symbols, etc. +// +// These buffers, while typically small, may need to be large for corner +// cases (e.g. templatized C++ symbols, or many DLLs loaded). Where do we +// allocate them? +// +// We may be in error handling for a stack overflow, so lets not put them on +// the stack. +// +// Dynamically allocating them may fail if we are handling a native OOM. It +// is also a bit dangerous, as the C heap may be corrupted already. +// +// That leaves pre-allocating them globally, which is safe and should always +// work (if we synchronize access) but incurs an undesirable footprint for +// non-error cases. +// +// We follow a two-way strategy: Allocate the buffers on the C heap in a +// reasonable large size. Failing that, fall back to static preallocated +// buffers. The size of the latter is large enough to handle common scenarios +// but small enough not to drive up the footprint too much (several kb). +// +// We keep these buffers around once allocated, for subsequent requests. This +// means that by running the initialization early at a safe time - before +// any error happens - buffers can be pre-allocated. This increases the chance +// of useful callstacks in error scenarios in exchange for a some cycles spent +// at startup. This behavior can be controlled with -XX:+InitializeDbgHelpEarly +// and is off by default. + +/////// + +// A simple buffer which attempts to allocate an optimal size but will +// fall back to a static minimally sized array on allocation error. +template +class SimpleBufferWithFallback { + T _fallback_buffer[MINIMAL_CAPACITY]; + T* _p; + int _capacity; + + // A sentinel at the end of the buffer to catch overflows. + void imprint_sentinel() { + assert(_p && _capacity > 0, "Buffer must be allocated"); + _p[_capacity - 1] = (T)'X'; + _capacity --; + } + +public: + + SimpleBufferWithFallback () + : _p(NULL), _capacity(0) + {} + + // Note: no destructor because these buffers should, once + // allocated, live until process end. + // ~SimpleBufferWithFallback() + + // Note: We use raw ::malloc/::free here instead of os::malloc()/os::free + // to prevent circularities or secondary crashes during error reporting. + virtual void initialize () { + assert(_p == NULL && _capacity == 0, "Only call once."); + const size_t bytes = OPTIMAL_CAPACITY * sizeof(T); + T* q = (T*) ::malloc(bytes); + if (q != NULL) { + _p = q; + _capacity = OPTIMAL_CAPACITY; + } else { + _p = _fallback_buffer; + _capacity = (int)(sizeof(_fallback_buffer) / sizeof(T)); + } + _p[0] = '\0'; + imprint_sentinel(); + } + + // We need a way to reset the buffer to fallback size for one special + // case, where two buffers need to be of identical capacity. + void reset_to_fallback_capacity() { + if (_p != _fallback_buffer) { + ::free(_p); + } + _p = _fallback_buffer; + _capacity = (int)(sizeof(_fallback_buffer) / sizeof(T)); + _p[0] = '\0'; + imprint_sentinel(); + } + + T* ptr() { return _p; } + const T* ptr() const { return _p; } + int capacity() const { return _capacity; } + +#ifdef ASSERT + void check() const { + assert(_p[_capacity] == (T)'X', "sentinel lost"); + } +#else + void check() const {} +#endif + +}; + +//// + +// ModuleHandleArray: a list holding module handles. Needs to be large enough +// to hold one handle per loaded DLL. +// Note: a standard OpenJDK loads normally ~30 libraries, including system +// libraries, without third party libraries. + +typedef SimpleBufferWithFallback ModuleHandleArrayBase; + +class ModuleHandleArray : public ModuleHandleArrayBase { + + int _num; // Number of handles in this array (may be < capacity). + +public: + + void initialize() { + ModuleHandleArrayBase::initialize(); + _num = 0; + } + + int num() const { return _num; } + void set_num(int n) { + assert(n <= capacity(), "Too large"); + _num = n; + } + + // Compare with another list; returns true if all handles are equal (incl. + // sort order) + bool equals(const ModuleHandleArray& other) const { + if (_num != other._num) { + return false; + } + if (::memcmp(ptr(), other.ptr(), _num * sizeof(HMODULE)) != 0) { + return false; + } + return true; + } + + // Copy content from other list. + void copy_content_from(ModuleHandleArray& other) { + assert(capacity() == other.capacity(), "Different capacities."); + memcpy(ptr(), other.ptr(), other._num * sizeof(HMODULE)); + _num = other._num; + } + +}; + +//// + +// PathBuffer: a buffer to hold and work with a pdb search PATH - a concatenation +// of multiple directories separated by ';'. +// A single directory name can be (NTFS) as long as 32K, but in reality is +// seldom larger than the (historical) MAX_PATH of 260. + +#define MINIMUM_PDB_PATH_LENGTH MAX_PATH * 4 +#define OPTIMAL_PDB_PATH_LENGTH MAX_PATH * 64 + +typedef SimpleBufferWithFallback PathBufferBase; + +class PathBuffer: public PathBufferBase { +public: + + // Search PDB path for a directory. Search is case insensitive. Returns + // true if directory was found in the path, false otherwise. + bool contains_directory(const char* directory) { + if (ptr() == NULL) { + return false; + } + const size_t len = strlen(directory); + if (len == 0) { + return false; + } + char* p = ptr(); + for(;;) { + char* q = strchr(p, ';'); + if (q != NULL) { + if (len == (q - p)) { + if (strnicmp(p, directory, len) == 0) { + return true; + } + } + p = q + 1; + } else { + // tail + return stricmp(p, directory) == 0 ? true : false; + } + } + return false; + } + + // Appends the given directory to the path. Returns false if internal + // buffer size was not sufficient. + bool append_directory(const char* directory) { + const size_t len = strlen(directory); + if (len == 0) { + return false; + } + char* p = ptr(); + const size_t len_now = strlen(p); + const size_t needs_capacity = len_now + 1 + len + 1; // xxx;yy\0 + if (needs_capacity > (size_t)capacity()) { + return false; // OOM + } + if (len_now > 0) { // Not the first path element. + p += len_now; + *p = ';'; + p ++; + } + strcpy(p, directory); + return true; + } + +}; + +// A simple buffer to hold one single file name. A file name can be (NTFS) as +// long as 32K, but in reality is seldom larger than MAX_PATH. +typedef SimpleBufferWithFallback FileNameBuffer; + +// A buffer to hold a C++ symbol. Usually small, but symbols may be larger for +// templates. +#define MINIMUM_SYMBOL_NAME_LEN 128 +#define OPTIMAL_SYMBOL_NAME_LEN 1024 + +typedef SimpleBufferWithFallback SymbolBuffer; + +static struct { + + // Two buffers to hold lists of loaded modules. handles across invocations of + // SymbolEngine::recalc_search_path(). + ModuleHandleArray loaded_modules; + ModuleHandleArray last_loaded_modules; + // Buffer to retrieve and assemble the pdb search path. + PathBuffer search_path; + // Buffer to retrieve directory names for loaded modules. + FileNameBuffer dir_name; + // Buffer to retrieve decoded symbol information (in SymbolEngine::decode) + SymbolBuffer decode_buffer; + + void initialize() { + search_path.initialize(); + dir_name.initialize(); + decode_buffer.initialize(); + + loaded_modules.initialize(); + last_loaded_modules.initialize(); + + // Note: both module lists must have the same capacity. If one allocation + // did fail, let them both fall back to the fallback size. + if (loaded_modules.capacity() != last_loaded_modules.capacity()) { + loaded_modules.reset_to_fallback_capacity(); + last_loaded_modules.reset_to_fallback_capacity(); + } + + assert(search_path.capacity() > 0 && dir_name.capacity() > 0 && + decode_buffer.capacity() > 0 && loaded_modules.capacity() > 0 && + last_loaded_modules.capacity() > 0, "Init error."); + } + +} g_buffers; + + +// Scan the loaded modules. +// +// For each loaded module, add the directory it is located in to the pdb search +// path, but avoid duplicates. Prior search path content is preserved. +// +// If p_search_path_was_updated is not NULL, points to a bool which, upon +// successful return from the function, contains true if the search path +// was updated, false if no update was needed because no new DLLs were +// loaded or unloaded. +// +// Returns true for success, false for error. +static bool recalc_search_path_locked(bool* p_search_path_was_updated) { + + if (p_search_path_was_updated) { + *p_search_path_was_updated = false; + } + + HANDLE hProcess = ::GetCurrentProcess(); + + BOOL success = false; + + // 1) Retrieve current set search path. + // (PDB search path is a global setting and someone might have modified + // it, so take care not to remove directories, just to add our own). + + if (!WindowsDbgHelp::symGetSearchPath(hProcess, g_buffers.search_path.ptr(), + (int)g_buffers.search_path.capacity())) { + return false; + } + DEBUG_ONLY(g_buffers.search_path.check();) + + // 2) Retrieve list of modules handles of all currently loaded modules. + DWORD bytes_needed = 0; + const DWORD buffer_capacity_bytes = (DWORD)g_buffers.loaded_modules.capacity() * sizeof(HMODULE); + success = ::EnumProcessModules(hProcess, g_buffers.loaded_modules.ptr(), + buffer_capacity_bytes, &bytes_needed); + DEBUG_ONLY(g_buffers.loaded_modules.check();) + + // Note: EnumProcessModules is sloppily defined in terms of whether a + // too-small output buffer counts as error. Will it truncate but still + // return TRUE? Nobody knows and the manpage is not telling. So we count + // truncation it as error, disregarding the return value. + if (!success || bytes_needed > buffer_capacity_bytes) { + return false; + } else { + const int num_modules = bytes_needed / sizeof(HMODULE); + g_buffers.loaded_modules.set_num(num_modules); + } + + // Compare the list of module handles with the last list. If the lists are + // identical, no additional dlls were loaded and we can stop. + if (g_buffers.loaded_modules.equals(g_buffers.last_loaded_modules)) { + return true; + } else { + // Remember the new set of module handles and continue. + g_buffers.last_loaded_modules.copy_content_from(g_buffers.loaded_modules); + } + + // 3) For each loaded module: retrieve directory from which it was loaded. + // Add directory to search path (but avoid duplicates). + + bool did_modify_searchpath = false; + + for (int i = 0; i < (int)g_buffers.loaded_modules.num(); i ++) { + + const HMODULE hMod = g_buffers.loaded_modules.ptr()[i]; + char* const filebuffer = g_buffers.dir_name.ptr(); + const int file_buffer_capacity = g_buffers.dir_name.capacity(); + const int len_returned = (int)::GetModuleFileName(hMod, filebuffer, (DWORD)file_buffer_capacity); + DEBUG_ONLY(g_buffers.dir_name.check();) + if (len_returned == 0) { + // Error. This is suspicious - this may happen if a module has just been + // unloaded concurrently after our call to EnumProcessModules and + // GetModuleFileName, but probably just indicates a coding error. + assert(false, "GetModuleFileName failed (%u)", ::GetLastError()); + } else if (len_returned == file_buffer_capacity) { + // Truncation. Just skip this module and continue with the next module. + continue; + } + + // Cut file name part off. + char* last_slash = ::strrchr(filebuffer, '\\'); + if (last_slash == NULL) { + last_slash = ::strrchr(filebuffer, '/'); + } + if (last_slash) { + *last_slash = '\0'; + } + + // If this is already part of the search path, ignore it, otherwise + // append to search path. + if (!g_buffers.search_path.contains_directory(filebuffer)) { + if (!g_buffers.search_path.append_directory(filebuffer)) { + return false; // oom + } + DEBUG_ONLY(g_buffers.search_path.check();) + did_modify_searchpath = true; + } + + } // for each loaded module. + + // If we did not modify the search path, nothing further needs to be done. + if (!did_modify_searchpath) { + return true; + } + + // Set the search path to its new value. + if (!WindowsDbgHelp::symSetSearchPath(hProcess, g_buffers.search_path.ptr())) { + return false; + } + + if (p_search_path_was_updated) { + *p_search_path_was_updated = true; + } + + return true; + +} + +static bool demangle_locked(const char* symbol, char *buf, int buflen) { + + return WindowsDbgHelp::unDecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE) > 0; + +} + +static bool decode_locked(const void* addr, char* buf, int buflen, int* offset, bool do_demangle) { + + assert(g_buffers.decode_buffer.capacity() >= (sizeof(IMAGEHLP_SYMBOL64) + MINIMUM_SYMBOL_NAME_LEN), + "Decode buffer too small."); + assert(buf != NULL && buflen > 0 && offset != NULL, "invalid output buffer."); + + DWORD64 displacement; + PIMAGEHLP_SYMBOL64 pSymbol = NULL; + bool success = false; + + pSymbol = (PIMAGEHLP_SYMBOL64) g_buffers.decode_buffer.ptr(); + pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + pSymbol->MaxNameLength = (DWORD)(g_buffers.decode_buffer.capacity() - sizeof(IMAGEHLP_SYMBOL64) - 1); + + // It is unclear how SymGetSymFromAddr64 handles truncation. Experiments + // show it will return TRUE but not zero terminate (which is a really bad + // combination). Lets be super careful. + ::memset(pSymbol->Name, 0, pSymbol->MaxNameLength); // To catch truncation. + + if (WindowsDbgHelp::symGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) { + success = true; + if (pSymbol->Name[pSymbol->MaxNameLength - 1] != '\0') { + // Symbol was truncated. Do not attempt to demangle. Instead, zero terminate the + // truncated string. We still return success - the truncated string may still + // be usable for the caller. + pSymbol->Name[pSymbol->MaxNameLength - 1] = '\0'; + do_demangle = false; + } + + // Attempt to demangle. + if (do_demangle && demangle_locked(pSymbol->Name, buf, buflen)) { + // ok. + } else { + ::strncpy(buf, pSymbol->Name, buflen - 1); + } + buf[buflen - 1] = '\0'; + + *offset = (int)displacement; + } + + DEBUG_ONLY(g_buffers.decode_buffer.check();) + + return success; +} + +static enum { + state_uninitialized = 0, + state_ready = 1, + state_error = 2 +} g_state = state_uninitialized; + +static void initialize() { + + assert(g_state == state_uninitialized, "wrong sequence"); + g_state = state_error; + + // 1) Initialize buffers. + g_buffers.initialize(); + + // 1) Call SymInitialize + HANDLE hProcess = ::GetCurrentProcess(); + WindowsDbgHelp::symSetOptions(SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_DEFERRED_LOADS | + SYMOPT_EXACT_SYMBOLS | SYMOPT_LOAD_LINES); + if (!WindowsDbgHelp::symInitialize(hProcess, NULL, TRUE)) { + return; + } + + // Note: we ignore any errors from this point on. The symbol engine may be + // usable enough. + g_state = state_ready; + + (void)recalc_search_path_locked(NULL); + +} + +///////////////////// External functions ////////////////////////// + +// All outside facing functions are synchronized. Also, we run +// initialization on first touch. + +static CRITICAL_SECTION g_cs; + +namespace { // Do not export. + class SymbolEngineEntry { + public: + SymbolEngineEntry() { + ::EnterCriticalSection(&g_cs); + if (g_state == state_uninitialized) { + initialize(); + } + } + ~SymbolEngineEntry() { + ::LeaveCriticalSection(&g_cs); + } + }; +} + +// Called at DLL_PROCESS_ATTACH. +void SymbolEngine::pre_initialize() { + ::InitializeCriticalSection(&g_cs); +} + +bool SymbolEngine::decode(const void* addr, char* buf, int buflen, int* offset, bool do_demangle) { + + assert(buf != NULL && buflen > 0 && offset != NULL, "Argument error"); + buf[0] = '\0'; + *offset = -1; + + if (addr == NULL) { + return false; + } + + SymbolEngineEntry entry_guard; + + // Try decoding the symbol once. If we fail, attempt to rebuild the + // symbol search path - maybe the pc points to a dll whose pdb file is + // outside our search path. Then do attempt the decode again. + bool success = decode_locked(addr, buf, buflen, offset, do_demangle); + if (!success) { + bool did_update_search_path = false; + if (recalc_search_path_locked(&did_update_search_path)) { + if (did_update_search_path) { + success = decode_locked(addr, buf, buflen, offset, do_demangle); + } + } + } + + return success; + +} + +bool SymbolEngine::demangle(const char* symbol, char *buf, int buflen) { + + SymbolEngineEntry entry_guard; + + return demangle_locked(symbol, buf, buflen); + +} + +bool SymbolEngine::recalc_search_path(bool* p_search_path_was_updated) { + + SymbolEngineEntry entry_guard; + + return recalc_search_path_locked(p_search_path_was_updated); + +} + +bool SymbolEngine::get_source_info(const void* addr, char* buf, size_t buflen, + int* line_no) +{ + assert(buf != NULL && buflen > 0 && line_no != NULL, "Argument error"); + buf[0] = '\0'; + *line_no = -1; + + if (addr == NULL) { + return false; + } + + SymbolEngineEntry entry_guard; + + IMAGEHLP_LINE64 lineinfo; + memset(&lineinfo, 0, sizeof(lineinfo)); + lineinfo.SizeOfStruct = sizeof(lineinfo); + DWORD displacement; + if (WindowsDbgHelp::symGetLineFromAddr64(::GetCurrentProcess(), (DWORD64)addr, + &displacement, &lineinfo)) { + if (buf != NULL && buflen > 0 && lineinfo.FileName != NULL) { + // We only return the file name, not the whole path. + char* p = lineinfo.FileName; + char* q = strrchr(lineinfo.FileName, '\\'); + if (q) { + p = q + 1; + } + ::strncpy(buf, p, buflen - 1); + buf[buflen - 1] = '\0'; + } + if (line_no != 0) { + *line_no = lineinfo.LineNumber; + } + return true; + } + return false; +} + +// Print one liner describing state (if library loaded, which functions are +// missing - if any, and the dbhelp API version) +void SymbolEngine::print_state_on(outputStream* st) { + + SymbolEngineEntry entry_guard; + + st->print("symbol engine: "); + + if (g_state == state_uninitialized) { + st->print("uninitialized."); + } else if (g_state == state_error) { + st->print("initialization error."); + } else { + st->print("initialized successfully"); + st->print(" - sym options: 0x%X", WindowsDbgHelp::symGetOptions()); + st->print(" - pdb path: "); + if (WindowsDbgHelp::symGetSearchPath(::GetCurrentProcess(), + g_buffers.search_path.ptr(), + (int)g_buffers.search_path.capacity())) { + st->print_raw(g_buffers.search_path.ptr()); + } else { + st->print_raw("(cannot be retrieved)"); + } + } + st->cr(); + +} diff --git a/src/hotspot/os/windows/symbolengine.hpp b/src/hotspot/os/windows/symbolengine.hpp new file mode 100644 index 00000000000..c01bd9fc93c --- /dev/null +++ b/src/hotspot/os/windows/symbolengine.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, SAP SE. 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. + * + */ + +#ifndef OS_WINDOWS_VM_SYMBOLENGINE_HPP +#define OS_WINDOWS_VM_SYMBOLENGINE_HPP + +class outputStream; + +namespace SymbolEngine { + + bool decode(const void* addr, char* buf, int buflen, int* offset, bool do_demangle); + + bool demangle(const char* symbol, char *buf, int buflen); + + // given an address, attempts to retrieve the source file and line number. + bool get_source_info(const void* addr, char* filename, size_t filename_len, + int* line_no); + + // Scan the loaded modules. Add all directories for all loaded modules + // to the current search path, unless they are already part of the search + // path. Prior search path content is preserved, directories are only + // added, never removed. + // If p_search_path_was_updated is not NULL, points to a bool which, upon + // successful return from the function, contains true if the search path + // was updated, false if no update was needed because no new DLLs were + // loaded or unloaded. + // Returns true for success, false for error. + bool recalc_search_path(bool* p_search_path_was_updated = NULL); + + // Print one liner describing state (if library loaded, which functions are + // missing - if any, and the dbhelp API version) + void print_state_on(outputStream* st); + + // Call at DLL_PROCESS_ATTACH. + void pre_initialize(); + +}; + +#endif // #ifndef OS_WINDOWS_VM_SYMBOLENGINE_HPP + + diff --git a/src/hotspot/os/windows/threadCritical_windows.cpp b/src/hotspot/os/windows/threadCritical_windows.cpp index b432f7bb078..66f19e91fc0 100644 --- a/src/hotspot/os/windows/threadCritical_windows.cpp +++ b/src/hotspot/os/windows/threadCritical_windows.cpp @@ -51,16 +51,6 @@ static DWORD lock_owner = -1; // and found them ~30 times slower than the critical region code. // -void ThreadCritical::initialize() { -} - -void ThreadCritical::release() { - assert(lock_owner == -1, "Mutex being deleted while owned."); - assert(lock_count == -1, "Mutex being deleted while recursively locked"); - assert(lock_event != NULL, "Sanity check"); - CloseHandle(lock_event); -} - ThreadCritical::ThreadCritical() { DWORD current_thread = GetCurrentThreadId(); diff --git a/src/hotspot/os/windows/windbghelp.cpp b/src/hotspot/os/windows/windbghelp.cpp index f7119583ed8..e55ecc1d5b3 100644 --- a/src/hotspot/os/windows/windbghelp.cpp +++ b/src/hotspot/os/windows/windbghelp.cpp @@ -116,38 +116,36 @@ static void initialize() { } + ///////////////////// External functions ////////////////////////// // All outside facing functions are synchronized. Also, we run // initialization on first touch. +static CRITICAL_SECTION g_cs; -// Call InitializeCriticalSection as early as possible. -class CritSect { - CRITICAL_SECTION cs; -public: - CritSect() { ::InitializeCriticalSection(&cs); } - void enter() { ::EnterCriticalSection(&cs); } - void leave() { ::LeaveCriticalSection(&cs); } -}; - -static CritSect g_cs; - -class EntryGuard { -public: - EntryGuard() { - g_cs.enter(); - if (g_state == state_uninitialized) { - initialize(); +namespace { // Do not export. + class WindowsDbgHelpEntry { + public: + WindowsDbgHelpEntry() { + ::EnterCriticalSection(&g_cs); + if (g_state == state_uninitialized) { + initialize(); + } } - } - ~EntryGuard() { - g_cs.leave(); - } -}; + ~WindowsDbgHelpEntry() { + ::LeaveCriticalSection(&g_cs); + } + }; +} + +// Called at DLL_PROCESS_ATTACH. +void WindowsDbgHelp::pre_initialize() { + ::InitializeCriticalSection(&g_cs); +} DWORD WindowsDbgHelp::symSetOptions(DWORD arg) { - EntryGuard entry_guard; + WindowsDbgHelpEntry entry_guard; if (g_pfn_SymSetOptions != NULL) { return g_pfn_SymSetOptions(arg); } @@ -155,7 +153,7 @@ DWORD WindowsDbgHelp::symSetOptions(DWORD arg) { } DWORD WindowsDbgHelp::symGetOptions(void) { - EntryGuard entry_guard; + WindowsDbgHelpEntry entry_guard; if (g_pfn_SymGetOptions != NULL) { return g_pfn_SymGetOptions(); } @@ -163,7 +161,7 @@ DWORD WindowsDbgHelp::symGetOptions(void) { } BOOL WindowsDbgHelp::symInitialize(HANDLE hProcess, PCTSTR UserSearchPath, BOOL fInvadeProcess) { - EntryGuard entry_guard; + WindowsDbgHelpEntry entry_guard; if (g_pfn_SymInitialize != NULL) { return g_pfn_SymInitialize(hProcess, UserSearchPath, fInvadeProcess); } @@ -172,7 +170,7 @@ BOOL WindowsDbgHelp::symInitialize(HANDLE hProcess, PCTSTR UserSearchPath, BOOL BOOL WindowsDbgHelp::symGetSymFromAddr64(HANDLE hProcess, DWORD64 the_address, PDWORD64 Displacement, PIMAGEHLP_SYMBOL64 Symbol) { - EntryGuard entry_guard; + WindowsDbgHelpEntry entry_guard; if (g_pfn_SymGetSymFromAddr64 != NULL) { return g_pfn_SymGetSymFromAddr64(hProcess, the_address, Displacement, Symbol); } @@ -181,7 +179,7 @@ BOOL WindowsDbgHelp::symGetSymFromAddr64(HANDLE hProcess, DWORD64 the_address, DWORD WindowsDbgHelp::unDecorateSymbolName(const char* DecoratedName, char* UnDecoratedName, DWORD UndecoratedLength, DWORD Flags) { - EntryGuard entry_guard; + WindowsDbgHelpEntry entry_guard; if (g_pfn_UnDecorateSymbolName != NULL) { return g_pfn_UnDecorateSymbolName(DecoratedName, UnDecoratedName, UndecoratedLength, Flags); } @@ -192,7 +190,7 @@ DWORD WindowsDbgHelp::unDecorateSymbolName(const char* DecoratedName, char* UnDe } BOOL WindowsDbgHelp::symSetSearchPath(HANDLE hProcess, PCTSTR SearchPath) { - EntryGuard entry_guard; + WindowsDbgHelpEntry entry_guard; if (g_pfn_SymSetSearchPath != NULL) { return g_pfn_SymSetSearchPath(hProcess, SearchPath); } @@ -200,7 +198,7 @@ BOOL WindowsDbgHelp::symSetSearchPath(HANDLE hProcess, PCTSTR SearchPath) { } BOOL WindowsDbgHelp::symGetSearchPath(HANDLE hProcess, PTSTR SearchPath, int SearchPathLength) { - EntryGuard entry_guard; + WindowsDbgHelpEntry entry_guard; if (g_pfn_SymGetSearchPath != NULL) { return g_pfn_SymGetSearchPath(hProcess, SearchPath, SearchPathLength); } @@ -212,7 +210,7 @@ BOOL WindowsDbgHelp::stackWalk64(DWORD MachineType, HANDLE hThread, LPSTACKFRAME64 StackFrame, PVOID ContextRecord) { - EntryGuard entry_guard; + WindowsDbgHelpEntry entry_guard; if (g_pfn_StackWalk64 != NULL) { return g_pfn_StackWalk64(MachineType, hProcess, hThread, StackFrame, ContextRecord, @@ -226,7 +224,7 @@ BOOL WindowsDbgHelp::stackWalk64(DWORD MachineType, } PVOID WindowsDbgHelp::symFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) { - EntryGuard entry_guard; + WindowsDbgHelpEntry entry_guard; if (g_pfn_SymFunctionTableAccess64 != NULL) { return g_pfn_SymFunctionTableAccess64(hProcess, AddrBase); } @@ -234,7 +232,7 @@ PVOID WindowsDbgHelp::symFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase } DWORD64 WindowsDbgHelp::symGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr) { - EntryGuard entry_guard; + WindowsDbgHelpEntry entry_guard; if (g_pfn_SymGetModuleBase64 != NULL) { return g_pfn_SymGetModuleBase64(hProcess, dwAddr); } @@ -245,7 +243,7 @@ BOOL WindowsDbgHelp::miniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam) { - EntryGuard entry_guard; + WindowsDbgHelpEntry entry_guard; if (g_pfn_MiniDumpWriteDump != NULL) { return g_pfn_MiniDumpWriteDump(hProcess, ProcessId, hFile, DumpType, ExceptionParam, UserStreamParam, CallbackParam); @@ -255,7 +253,7 @@ BOOL WindowsDbgHelp::miniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE BOOL WindowsDbgHelp::symGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line) { - EntryGuard entry_guard; + WindowsDbgHelpEntry entry_guard; if (g_pfn_SymGetLineFromAddr64 != NULL) { return g_pfn_SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, Line); } diff --git a/src/hotspot/os/windows/windbghelp.hpp b/src/hotspot/os/windows/windbghelp.hpp index 1aaa9e4965a..97dddbc9aa5 100644 --- a/src/hotspot/os/windows/windbghelp.hpp +++ b/src/hotspot/os/windows/windbghelp.hpp @@ -66,6 +66,9 @@ namespace WindowsDbgHelp { // missing - if any, and the dbhelp API version) void print_state_on(outputStream* st); + // Call at DLL_PROCESS_ATTACH. + void pre_initialize(); + }; diff --git a/src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp b/src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp index cbf54b82c0b..ec124e8e2a6 100644 --- a/src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp +++ b/src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp @@ -34,22 +34,6 @@ // Implementation of class atomic -inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; } - -inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } - -inline jlong Atomic::load(const volatile jlong* src) { return *src; } - // // machine barrier instructions: // @@ -148,90 +132,15 @@ inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) co return result; } - -inline void Atomic::inc (volatile jint* dest) { - - unsigned int temp; - - __asm__ __volatile__ ( - strasm_nobarrier - "1: lwarx %0, 0, %2 \n" - " addic %0, %0, 1 \n" - " stwcx. %0, 0, %2 \n" - " bne- 1b \n" - strasm_nobarrier - : /*%0*/"=&r" (temp), "=m" (*dest) - : /*%2*/"r" (dest), "m" (*dest) - : "cc" strasm_nobarrier_clobber_memory); - -} - -inline void Atomic::inc_ptr(volatile intptr_t* dest) { - - long temp; - - __asm__ __volatile__ ( - strasm_nobarrier - "1: ldarx %0, 0, %2 \n" - " addic %0, %0, 1 \n" - " stdcx. %0, 0, %2 \n" - " bne- 1b \n" - strasm_nobarrier - : /*%0*/"=&r" (temp), "=m" (*dest) - : /*%2*/"r" (dest), "m" (*dest) - : "cc" strasm_nobarrier_clobber_memory); - -} - -inline void Atomic::inc_ptr(volatile void* dest) { - inc_ptr((volatile intptr_t*)dest); -} - - -inline void Atomic::dec (volatile jint* dest) { - - unsigned int temp; - - __asm__ __volatile__ ( - strasm_nobarrier - "1: lwarx %0, 0, %2 \n" - " addic %0, %0, -1 \n" - " stwcx. %0, 0, %2 \n" - " bne- 1b \n" - strasm_nobarrier - : /*%0*/"=&r" (temp), "=m" (*dest) - : /*%2*/"r" (dest), "m" (*dest) - : "cc" strasm_nobarrier_clobber_memory); - -} - -inline void Atomic::dec_ptr(volatile intptr_t* dest) { - - long temp; - - __asm__ __volatile__ ( - strasm_nobarrier - "1: ldarx %0, 0, %2 \n" - " addic %0, %0, -1 \n" - " stdcx. %0, 0, %2 \n" - " bne- 1b \n" - strasm_nobarrier - : /*%0*/"=&r" (temp), "=m" (*dest) - : /*%2*/"r" (dest), "m" (*dest) - : "cc" strasm_nobarrier_clobber_memory); - -} - -inline void Atomic::dec_ptr(volatile void* dest) { - dec_ptr((volatile intptr_t*)dest); -} - -inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) { - - // Note that xchg_ptr doesn't necessarily do an acquire +template<> +template +inline T Atomic::PlatformXchg<4>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(4 == sizeof(T)); + // Note that xchg doesn't necessarily do an acquire // (see synchronizer.cpp). - unsigned int old_value; + T old_value; const uint64_t zero = 0; __asm__ __volatile__ ( @@ -259,15 +168,18 @@ inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) { "memory" ); - return (jint) old_value; + return old_value; } -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { - - // Note that xchg_ptr doesn't necessarily do an acquire +template<> +template +inline T Atomic::PlatformXchg<8>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + // Note that xchg doesn't necessarily do an acquire // (see synchronizer.cpp). - long old_value; + T old_value; const uint64_t zero = 0; __asm__ __volatile__ ( @@ -295,11 +207,7 @@ inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* des "memory" ); - return (intptr_t) old_value; -} - -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); + return old_value; } inline void cmpxchg_pre_membar(cmpxchg_memory_order order) { diff --git a/src/hotspot/os_cpu/aix_ppc/orderAccess_aix_ppc.inline.hpp b/src/hotspot/os_cpu/aix_ppc/orderAccess_aix_ppc.inline.hpp index b6214c15aea..7e71e11d2a3 100644 --- a/src/hotspot/os_cpu/aix_ppc/orderAccess_aix_ppc.inline.hpp +++ b/src/hotspot/os_cpu/aix_ppc/orderAccess_aix_ppc.inline.hpp @@ -78,16 +78,17 @@ inline void OrderAccess::acquire() { inlasm_lwsync(); } inline void OrderAccess::release() { inlasm_lwsync(); } inline void OrderAccess::fence() { inlasm_sync(); } -template<> inline jbyte OrderAccess::specialized_load_acquire (const volatile jbyte* p) { register jbyte t = load(p); inlasm_acquire_reg(t); return t; } -template<> inline jshort OrderAccess::specialized_load_acquire(const volatile jshort* p) { register jshort t = load(p); inlasm_acquire_reg(t); return t; } -template<> inline jint OrderAccess::specialized_load_acquire (const volatile jint* p) { register jint t = load(p); inlasm_acquire_reg(t); return t; } -template<> inline jlong OrderAccess::specialized_load_acquire (const volatile jlong* p) { register jlong t = load(p); inlasm_acquire_reg(t); return t; } +template +struct OrderAccess::PlatformOrderedLoad + VALUE_OBJ_CLASS_SPEC +{ + template + T operator()(const volatile T* p) const { register T t = Atomic::load(p); inlasm_acquire_reg(t); return t; } +}; #undef inlasm_sync #undef inlasm_lwsync #undef inlasm_eieio #undef inlasm_isync -#define VM_HAS_GENERALIZED_ORDER_ACCESS 1 - #endif // OS_CPU_AIX_OJDKPPC_VM_ORDERACCESS_AIX_PPC_INLINE_HPP diff --git a/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp index 77528598d15..458dcf242c8 100644 --- a/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp +++ b/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp @@ -27,19 +27,6 @@ // Implementation of class atomic -inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; } - -inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } - - template struct Atomic::PlatformAdd : Atomic::FetchAndAdd > @@ -61,25 +48,11 @@ inline D Atomic::PlatformAdd<4>::fetch_and_add(I add_value, D volatile* dest) co return old_value; } -inline void Atomic::inc (volatile jint* dest) { - __asm__ volatile ( "lock addl $1,(%0)" : - : "r" (dest) : "cc", "memory"); -} - -inline void Atomic::inc_ptr(volatile void* dest) { - inc_ptr((volatile intptr_t*)dest); -} - -inline void Atomic::dec (volatile jint* dest) { - __asm__ volatile ( "lock subl $1,(%0)" : - : "r" (dest) : "cc", "memory"); -} - -inline void Atomic::dec_ptr(volatile void* dest) { - dec_ptr((volatile intptr_t*)dest); -} - -inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) { +template<> +template +inline T Atomic::PlatformXchg<4>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(4 == sizeof(T)); __asm__ volatile ( "xchgl (%2),%0" : "=r" (exchange_value) : "0" (exchange_value), "r" (dest) @@ -87,10 +60,6 @@ inline jint Atomic::xchg (jint exchange_value, volatile jint* des return exchange_value; } -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); -} - template<> template inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, @@ -120,9 +89,6 @@ inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, } #ifdef AMD64 -inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } - template<> template inline D Atomic::PlatformAdd<8>::fetch_and_add(I add_value, D volatile* dest) const { @@ -136,21 +102,11 @@ inline D Atomic::PlatformAdd<8>::fetch_and_add(I add_value, D volatile* dest) co return old_value; } -inline void Atomic::inc_ptr(volatile intptr_t* dest) { - __asm__ __volatile__ ( "lock addq $1,(%0)" - : - : "r" (dest) - : "cc", "memory"); -} - -inline void Atomic::dec_ptr(volatile intptr_t* dest) { - __asm__ __volatile__ ( "lock subq $1,(%0)" - : - : "r" (dest) - : "cc", "memory"); -} - -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { +template<> +template +inline T Atomic::PlatformXchg<8>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); __asm__ __volatile__ ("xchgq (%2),%0" : "=r" (exchange_value) : "0" (exchange_value), "r" (dest) @@ -172,22 +128,8 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, return exchange_value; } -inline jlong Atomic::load(const volatile jlong* src) { return *src; } - #else // !AMD64 -inline void Atomic::inc_ptr(volatile intptr_t* dest) { - inc((volatile jint*)dest); -} - -inline void Atomic::dec_ptr(volatile intptr_t* dest) { - dec((volatile jint*)dest); -} - -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { - return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest); -} - extern "C" { // defined in bsd_x86.s jlong _Atomic_cmpxchg_long(jlong, volatile jlong*, jlong, bool); @@ -204,18 +146,21 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, return cmpxchg_using_helper(_Atomic_cmpxchg_long, exchange_value, dest, compare_value); } -inline jlong Atomic::load(const volatile jlong* src) { +template<> +template +inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const { + STATIC_ASSERT(8 == sizeof(T)); volatile jlong dest; - _Atomic_move_long(src, &dest); - return dest; + _Atomic_move_long(reinterpret_cast(src), reinterpret_cast(&dest)); + return PrimitiveConversions::cast(dest); } -inline void Atomic::store(jlong store_value, jlong* dest) { - _Atomic_move_long((volatile jlong*)&store_value, (volatile jlong*)dest); -} - -inline void Atomic::store(jlong store_value, volatile jlong* dest) { - _Atomic_move_long((volatile jlong*)&store_value, dest); +template<> +template +inline void Atomic::PlatformStore<8>::operator()(T store_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + _Atomic_move_long(reinterpret_cast(&store_value), reinterpret_cast(dest)); } #endif // AMD64 diff --git a/src/hotspot/os_cpu/bsd_x86/orderAccess_bsd_x86.inline.hpp b/src/hotspot/os_cpu/bsd_x86/orderAccess_bsd_x86.inline.hpp index 038d6f985d5..d2b0674a36d 100644 --- a/src/hotspot/os_cpu/bsd_x86/orderAccess_bsd_x86.inline.hpp +++ b/src/hotspot/os_cpu/bsd_x86/orderAccess_bsd_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -64,46 +64,57 @@ inline void OrderAccess::fence() { } template<> -inline void OrderAccess::specialized_release_store_fence (volatile jbyte* p, jbyte v) { - __asm__ volatile ( "xchgb (%2),%0" - : "=q" (v) - : "0" (v), "r" (p) - : "memory"); -} +struct OrderAccess::PlatformOrderedStore<1, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm__ volatile ( "xchgb (%2),%0" + : "=q" (v) + : "0" (v), "r" (p) + : "memory"); + } +}; + template<> -inline void OrderAccess::specialized_release_store_fence(volatile jshort* p, jshort v) { - __asm__ volatile ( "xchgw (%2),%0" - : "=r" (v) - : "0" (v), "r" (p) - : "memory"); -} +struct OrderAccess::PlatformOrderedStore<2, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm__ volatile ( "xchgw (%2),%0" + : "=r" (v) + : "0" (v), "r" (p) + : "memory"); + } +}; + template<> -inline void OrderAccess::specialized_release_store_fence (volatile jint* p, jint v) { - __asm__ volatile ( "xchgl (%2),%0" - : "=r" (v) - : "0" (v), "r" (p) - : "memory"); -} +struct OrderAccess::PlatformOrderedStore<4, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm__ volatile ( "xchgl (%2),%0" + : "=r" (v) + : "0" (v), "r" (p) + : "memory"); + } +}; #ifdef AMD64 template<> -inline void OrderAccess::specialized_release_store_fence (volatile jlong* p, jlong v) { - __asm__ volatile ( "xchgq (%2), %0" - : "=r" (v) - : "0" (v), "r" (p) - : "memory"); -} +struct OrderAccess::PlatformOrderedStore<8, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm__ volatile ( "xchgq (%2), %0" + : "=r" (v) + : "0" (v), "r" (p) + : "memory"); + } +}; #endif // AMD64 -template<> -inline void OrderAccess::specialized_release_store_fence (volatile jfloat* p, jfloat v) { - release_store_fence((volatile jint*)p, jint_cast(v)); -} -template<> -inline void OrderAccess::specialized_release_store_fence(volatile jdouble* p, jdouble v) { - release_store_fence((volatile jlong*)p, jlong_cast(v)); -} - -#define VM_HAS_GENERALIZED_ORDER_ACCESS 1 - #endif // OS_CPU_BSD_X86_VM_ORDERACCESS_BSD_X86_INLINE_HPP diff --git a/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp b/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp index 7fcaf785f9a..0daea3c6c4b 100644 --- a/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp +++ b/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp @@ -87,7 +87,7 @@ static inline int m68k_add_and_fetch(int add_value, volatile int *ptr) { /* Atomically write VALUE into `*PTR' and returns the previous contents of `*PTR'. */ -static inline int m68k_lock_test_and_set(volatile int *ptr, int newval) { +static inline int m68k_lock_test_and_set(int newval, volatile int *ptr) { for (;;) { // Loop until success. int prev = *ptr; @@ -148,7 +148,7 @@ static inline int arm_add_and_fetch(int add_value, volatile int *ptr) { /* Atomically write VALUE into `*PTR' and returns the previous contents of `*PTR'. */ -static inline int arm_lock_test_and_set(volatile int *ptr, int newval) { +static inline int arm_lock_test_and_set(int newval, volatile int *ptr) { for (;;) { // Loop until a __kernel_cmpxchg succeeds. int prev = *ptr; @@ -159,20 +159,6 @@ static inline int arm_lock_test_and_set(volatile int *ptr, int newval) { } #endif // ARM -inline void Atomic::store(jint store_value, volatile jint* dest) { -#if !defined(ARM) && !defined(M68K) - __sync_synchronize(); -#endif - *dest = store_value; -} - -inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { -#if !defined(ARM) && !defined(M68K) - __sync_synchronize(); -#endif - *dest = store_value; -} - template struct Atomic::PlatformAdd : Atomic::AddAndFetch > @@ -207,42 +193,22 @@ inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) co return __sync_add_and_fetch(dest, add_value); } -inline void Atomic::inc(volatile jint* dest) { - add(1, dest); -} - -inline void Atomic::inc_ptr(volatile intptr_t* dest) { - add_ptr(1, dest); -} - -inline void Atomic::inc_ptr(volatile void* dest) { - add_ptr(1, dest); -} - -inline void Atomic::dec(volatile jint* dest) { - add(-1, dest); -} - -inline void Atomic::dec_ptr(volatile intptr_t* dest) { - add_ptr(-1, dest); -} - -inline void Atomic::dec_ptr(volatile void* dest) { - add_ptr(-1, dest); -} - -inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) { +template<> +template +inline T Atomic::PlatformXchg<4>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(4 == sizeof(T)); #ifdef ARM - return arm_lock_test_and_set(dest, exchange_value); + return xchg_using_helper(arm_lock_test_and_set, exchange_value, dest); #else #ifdef M68K - return m68k_lock_test_and_set(dest, exchange_value); + return xchg_using_helper(m68k_lock_test_and_set, exchange_value, dest); #else // __sync_lock_test_and_set is a bizarrely named atomic exchange // operation. Note that some platforms only support this with the // limitation that the only valid value to store is the immediate // constant 1. There is a test for this in JNI_CreateJavaVM(). - jint result = __sync_lock_test_and_set (dest, exchange_value); + T result = __sync_lock_test_and_set (dest, exchange_value); // All atomic operations are expected to be full memory barriers // (see atomic.hpp). However, __sync_lock_test_and_set is not // a full memory barrier, but an acquire barrier. Hence, this added @@ -253,24 +219,14 @@ inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) { #endif // ARM } -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, - volatile intptr_t* dest) { -#ifdef ARM - return arm_lock_test_and_set(dest, exchange_value); -#else -#ifdef M68K - return m68k_lock_test_and_set(dest, exchange_value); -#else - intptr_t result = __sync_lock_test_and_set (dest, exchange_value); +template<> +template +inline T Atomic::PlatformXchg<8>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + T result = __sync_lock_test_and_set (dest, exchange_value); __sync_synchronize(); return result; -#endif // M68K -#endif // ARM -} - -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void *) xchg_ptr((intptr_t) exchange_value, - (volatile intptr_t*) dest); } // No direct support for cmpxchg of bytes; emulate using int. @@ -305,18 +261,21 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, return __sync_val_compare_and_swap(dest, compare_value, exchange_value); } -inline jlong Atomic::load(const volatile jlong* src) { +template<> +template +inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const { + STATIC_ASSERT(8 == sizeof(T)); volatile jlong dest; - os::atomic_copy64(src, &dest); - return dest; + os::atomic_copy64(reinterpret_cast(src), reinterpret_cast(&dest)); + return PrimitiveConversions::cast(dest); } -inline void Atomic::store(jlong store_value, jlong* dest) { - os::atomic_copy64((volatile jlong*)&store_value, (volatile jlong*)dest); -} - -inline void Atomic::store(jlong store_value, volatile jlong* dest) { - os::atomic_copy64((volatile jlong*)&store_value, dest); +template<> +template +inline void Atomic::PlatformStore<8>::operator()(T store_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + os::atomic_copy64(reinterpret_cast(&store_value), reinterpret_cast(dest)); } #endif // OS_CPU_BSD_ZERO_VM_ATOMIC_BSD_ZERO_HPP diff --git a/src/hotspot/os_cpu/bsd_zero/orderAccess_bsd_zero.inline.hpp b/src/hotspot/os_cpu/bsd_zero/orderAccess_bsd_zero.inline.hpp index fb3017ce9d1..96ea19a4a70 100644 --- a/src/hotspot/os_cpu/bsd_zero/orderAccess_bsd_zero.inline.hpp +++ b/src/hotspot/os_cpu/bsd_zero/orderAccess_bsd_zero.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -74,6 +74,4 @@ inline void OrderAccess::acquire() { LIGHT_MEM_BARRIER; } inline void OrderAccess::release() { LIGHT_MEM_BARRIER; } inline void OrderAccess::fence() { FULL_MEM_BARRIER; } -#define VM_HAS_GENERALIZED_ORDER_ACCESS 1 - #endif // OS_CPU_BSD_ZERO_VM_ORDERACCESS_BSD_ZERO_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp index 4074df4fe5a..e4076609924 100644 --- a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp @@ -34,19 +34,6 @@ #define READ_MEM_BARRIER __atomic_thread_fence(__ATOMIC_ACQUIRE); #define WRITE_MEM_BARRIER __atomic_thread_fence(__ATOMIC_RELEASE); -inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; } - -inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } - - template struct Atomic::PlatformAdd : Atomic::AddAndFetch > @@ -57,39 +44,16 @@ struct Atomic::PlatformAdd } }; -inline void Atomic::inc(volatile jint* dest) -{ - add(1, dest); -} - -inline void Atomic::inc_ptr(volatile void* dest) -{ - add_ptr(1, dest); -} - -inline void Atomic::dec (volatile jint* dest) -{ - add(-1, dest); -} - -inline void Atomic::dec_ptr(volatile void* dest) -{ - add_ptr(-1, dest); -} - -inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) -{ - jint res = __sync_lock_test_and_set (dest, exchange_value); +template +template +inline T Atomic::PlatformXchg::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(byte_size == sizeof(T)); + T res = __sync_lock_test_and_set(dest, exchange_value); FULL_MEM_BARRIER; return res; } -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) -{ - return (void *) xchg_ptr((intptr_t) exchange_value, - (volatile intptr_t*) dest); -} - template template inline T Atomic::PlatformCmpxchg::operator()(T exchange_value, @@ -107,26 +71,4 @@ inline T Atomic::PlatformCmpxchg::operator()(T exchange_value, } } -inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } - -inline void Atomic::inc_ptr(volatile intptr_t* dest) -{ - add_ptr(1, dest); -} - -inline void Atomic::dec_ptr(volatile intptr_t* dest) -{ - add_ptr(-1, dest); -} - -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) -{ - intptr_t res = __sync_lock_test_and_set (dest, exchange_value); - FULL_MEM_BARRIER; - return res; -} - -inline jlong Atomic::load(const volatile jlong* src) { return *src; } - #endif // OS_CPU_LINUX_AARCH64_VM_ATOMIC_LINUX_AARCH64_HPP diff --git a/src/hotspot/os_cpu/linux_aarch64/orderAccess_linux_aarch64.inline.hpp b/src/hotspot/os_cpu/linux_aarch64/orderAccess_linux_aarch64.inline.hpp index dcbce021456..32164dd3058 100644 --- a/src/hotspot/os_cpu/linux_aarch64/orderAccess_linux_aarch64.inline.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/orderAccess_linux_aarch64.inline.hpp @@ -50,93 +50,28 @@ inline void OrderAccess::fence() { FULL_MEM_BARRIER; } -inline jbyte OrderAccess::load_acquire(const volatile jbyte* p) -{ jbyte data; __atomic_load(p, &data, __ATOMIC_ACQUIRE); return data; } -inline jshort OrderAccess::load_acquire(const volatile jshort* p) -{ jshort data; __atomic_load(p, &data, __ATOMIC_ACQUIRE); return data; } -inline jint OrderAccess::load_acquire(const volatile jint* p) -{ jint data; __atomic_load(p, &data, __ATOMIC_ACQUIRE); return data; } -inline jlong OrderAccess::load_acquire(const volatile jlong* p) -{ jlong data; __atomic_load(p, &data, __ATOMIC_ACQUIRE); return data; } -inline jubyte OrderAccess::load_acquire(const volatile jubyte* p) -{ jubyte data; __atomic_load(p, &data, __ATOMIC_ACQUIRE); return data; } -inline jushort OrderAccess::load_acquire(const volatile jushort* p) -{ jushort data; __atomic_load(p, &data, __ATOMIC_ACQUIRE); return data; } -inline juint OrderAccess::load_acquire(const volatile juint* p) -{ juint data; __atomic_load(p, &data, __ATOMIC_ACQUIRE); return data; } -inline julong OrderAccess::load_acquire(const volatile julong* p) -{ julong data; __atomic_load(p, &data, __ATOMIC_ACQUIRE); return data; } -inline jfloat OrderAccess::load_acquire(const volatile jfloat* p) -{ jfloat data; __atomic_load(p, &data, __ATOMIC_ACQUIRE); return data; } -inline jdouble OrderAccess::load_acquire(const volatile jdouble* p) -{ jdouble data; __atomic_load(p, &data, __ATOMIC_ACQUIRE); return data; } -inline intptr_t OrderAccess::load_ptr_acquire(const volatile intptr_t* p) -{ intptr_t data; __atomic_load(p, &data, __ATOMIC_ACQUIRE); return data; } -inline void* OrderAccess::load_ptr_acquire(const volatile void* p) -{ void* data; __atomic_load((void* const volatile *)p, &data, __ATOMIC_ACQUIRE); return data; } +template +struct OrderAccess::PlatformOrderedLoad + VALUE_OBJ_CLASS_SPEC +{ + template + T operator()(const volatile T* p) const { T data; __atomic_load(p, &data, __ATOMIC_ACQUIRE); return data; } +}; -inline void OrderAccess::release_store(volatile jbyte* p, jbyte v) -{ __atomic_store(p, &v, __ATOMIC_RELEASE); } -inline void OrderAccess::release_store(volatile jshort* p, jshort v) -{ __atomic_store(p, &v, __ATOMIC_RELEASE); } -inline void OrderAccess::release_store(volatile jint* p, jint v) -{ __atomic_store(p, &v, __ATOMIC_RELEASE); } -inline void OrderAccess::release_store(volatile jlong* p, jlong v) -{ __atomic_store(p, &v, __ATOMIC_RELEASE); } -inline void OrderAccess::release_store(volatile jubyte* p, jubyte v) -{ __atomic_store(p, &v, __ATOMIC_RELEASE); } -inline void OrderAccess::release_store(volatile jushort* p, jushort v) -{ __atomic_store(p, &v, __ATOMIC_RELEASE); } -inline void OrderAccess::release_store(volatile juint* p, juint v) -{ __atomic_store(p, &v, __ATOMIC_RELEASE); } -inline void OrderAccess::release_store(volatile julong* p, julong v) -{ __atomic_store(p, &v, __ATOMIC_RELEASE); } -inline void OrderAccess::release_store(volatile jfloat* p, jfloat v) -{ __atomic_store(p, &v, __ATOMIC_RELEASE); } -inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) -{ __atomic_store(p, &v, __ATOMIC_RELEASE); } -inline void OrderAccess::release_store_ptr(volatile intptr_t* p, intptr_t v) -{ __atomic_store(p, &v, __ATOMIC_RELEASE); } -inline void OrderAccess::release_store_ptr(volatile void* p, void* v) -{ __atomic_store((void* volatile *)p, &v, __ATOMIC_RELEASE); } +template +struct OrderAccess::PlatformOrderedStore + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { __atomic_store(p, &v, __ATOMIC_RELEASE); } +}; -inline void OrderAccess::store_fence(jbyte* p, jbyte v) -{ __atomic_store(p, &v, __ATOMIC_RELAXED); fence(); } -inline void OrderAccess::store_fence(jshort* p, jshort v) -{ __atomic_store(p, &v, __ATOMIC_RELAXED); fence(); } -inline void OrderAccess::store_fence(jint* p, jint v) -{ __atomic_store(p, &v, __ATOMIC_RELAXED); fence(); } -inline void OrderAccess::store_fence(jlong* p, jlong v) -{ __atomic_store(p, &v, __ATOMIC_RELAXED); fence(); } -inline void OrderAccess::store_fence(jubyte* p, jubyte v) -{ __atomic_store(p, &v, __ATOMIC_RELAXED); fence(); } -inline void OrderAccess::store_fence(jushort* p, jushort v) -{ __atomic_store(p, &v, __ATOMIC_RELAXED); fence(); } -inline void OrderAccess::store_fence(juint* p, juint v) -{ __atomic_store(p, &v, __ATOMIC_RELAXED); fence(); } -inline void OrderAccess::store_fence(julong* p, julong v) -{ __atomic_store(p, &v, __ATOMIC_RELAXED); fence(); } -inline void OrderAccess::store_fence(jfloat* p, jfloat v) -{ __atomic_store(p, &v, __ATOMIC_RELAXED); fence(); } -inline void OrderAccess::store_fence(jdouble* p, jdouble v) -{ __atomic_store(p, &v, __ATOMIC_RELAXED); fence(); } -inline void OrderAccess::store_ptr_fence(intptr_t* p, intptr_t v) -{ __atomic_store(p, &v, __ATOMIC_RELAXED); fence(); } -inline void OrderAccess::store_ptr_fence(void** p, void* v) -{ __atomic_store(p, &v, __ATOMIC_RELAXED); fence(); } - -inline void OrderAccess::release_store_fence(volatile jbyte* p, jbyte v) { release_store(p, v); fence(); } -inline void OrderAccess::release_store_fence(volatile jshort* p, jshort v) { release_store(p, v); fence(); } -inline void OrderAccess::release_store_fence(volatile jint* p, jint v) { release_store(p, v); fence(); } -inline void OrderAccess::release_store_fence(volatile jlong* p, jlong v) { release_store(p, v); fence(); } -inline void OrderAccess::release_store_fence(volatile jubyte* p, jubyte v) { release_store(p, v); fence(); } -inline void OrderAccess::release_store_fence(volatile jushort* p, jushort v) { release_store(p, v); fence(); } -inline void OrderAccess::release_store_fence(volatile juint* p, juint v) { release_store(p, v); fence(); } -inline void OrderAccess::release_store_fence(volatile julong* p, julong v) { release_store(p, v); fence(); } -inline void OrderAccess::release_store_fence(volatile jfloat* p, jfloat v) { release_store(p, v); fence(); } -inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { release_store(p, v); fence(); } - -inline void OrderAccess::release_store_ptr_fence(volatile intptr_t* p, intptr_t v) { release_store_ptr(p, v); fence(); } -inline void OrderAccess::release_store_ptr_fence(volatile void* p, void* v) { release_store_ptr(p, v); fence(); } +template +struct OrderAccess::PlatformOrderedStore + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { release_store(p, v); fence(); } +}; #endif // OS_CPU_LINUX_AARCH64_VM_ORDERACCESS_LINUX_AARCH64_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp b/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp index fcd7e1f9ba2..d5c6ecd9f8d 100644 --- a/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp +++ b/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp @@ -44,39 +44,24 @@ * kernel source or kernel_user_helpers.txt in Linux Doc. */ -inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; } +#ifndef AARCH64 +template<> +template +inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const { + STATIC_ASSERT(8 == sizeof(T)); + return PrimitiveConversions::cast( + (*os::atomic_load_long_func)(reinterpret_cast(src))); +} -inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } - -inline jlong Atomic::load (const volatile jlong* src) { - assert(((intx)src & (sizeof(jlong)-1)) == 0, "Atomic load jlong mis-aligned"); -#ifdef AARCH64 - return *src; -#else - return (*os::atomic_load_long_func)(src); +template<> +template +inline void Atomic::PlatformStore<8>::operator()(T store_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + (*os::atomic_store_long_func)( + PrimitiveConversions::cast(store_value), reinterpret_cast(dest)); +} #endif -} - -inline void Atomic::store (jlong value, volatile jlong* dest) { - assert(((intx)dest & (sizeof(jlong)-1)) == 0, "Atomic store jlong mis-aligned"); -#ifdef AARCH64 - *dest = value; -#else - (*os::atomic_store_long_func)(value, dest); -#endif -} - -inline void Atomic::store (jlong value, jlong* dest) { - store(value, (volatile jlong*)dest); -} // As per atomic.hpp all read-modify-write operations have to provide two-way // barriers semantics. For AARCH64 we are using load-acquire-with-reservation and @@ -122,14 +107,6 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co #endif } -inline void Atomic::inc(volatile jint* dest) { - Atomic::add(1, (volatile jint *)dest); -} - -inline void Atomic::dec(volatile jint* dest) { - Atomic::add(-1, (volatile jint *)dest); -} - #ifdef AARCH64 template<> template @@ -149,28 +126,15 @@ inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) co : "memory"); return val; } -#endif // AARCH64 +#endif -inline void Atomic::inc_ptr(volatile intptr_t* dest) { - Atomic::add_ptr(1, dest); -} - -inline void Atomic::dec_ptr(volatile intptr_t* dest) { - Atomic::add_ptr(-1, dest); -} - -inline void Atomic::inc_ptr(volatile void* dest) { - inc_ptr((volatile intptr_t*)dest); -} - -inline void Atomic::dec_ptr(volatile void* dest) { - dec_ptr((volatile intptr_t*)dest); -} - - -inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) { +template<> +template +inline T Atomic::PlatformXchg<4>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(4 == sizeof(T)); #ifdef AARCH64 - jint old_val; + T old_val; int tmp; __asm__ volatile( "1:\n\t" @@ -182,13 +146,17 @@ inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) { : "memory"); return old_val; #else - return (*os::atomic_xchg_func)(exchange_value, dest); + return xchg_using_helper(os::atomic_xchg_func, exchange_value, dest); #endif } -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { #ifdef AARCH64 - intptr_t old_val; +template<> +template +inline T Atomic::PlatformXchg<8>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + T old_val; int tmp; __asm__ volatile( "1:\n\t" @@ -199,14 +167,8 @@ inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* des : [new_val] "r" (exchange_value), [dest] "r" (dest) : "memory"); return old_val; -#else - return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest); -#endif -} - -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); } +#endif // AARCH64 // The memory_order parameter is ignored - we always provide the strongest/most-conservative ordering diff --git a/src/hotspot/os_cpu/linux_arm/orderAccess_linux_arm.inline.hpp b/src/hotspot/os_cpu/linux_arm/orderAccess_linux_arm.inline.hpp index a115dd82311..4a737c12a90 100644 --- a/src/hotspot/os_cpu/linux_arm/orderAccess_linux_arm.inline.hpp +++ b/src/hotspot/os_cpu/linux_arm/orderAccess_linux_arm.inline.hpp @@ -33,7 +33,6 @@ // - we define the high level barriers below and use the general // implementation in orderAccess.inline.hpp, with customizations // on AARCH64 via the specialized_* template functions -#define VM_HAS_GENERALIZED_ORDER_ACCESS 1 // Memory Ordering on ARM is weak. // @@ -131,91 +130,126 @@ inline void OrderAccess::fence() { dmb_sy(); } #ifdef AARCH64 -template<> inline jbyte OrderAccess::specialized_load_acquire(const volatile jbyte* p) { - volatile jbyte result; - __asm__ volatile( - "ldarb %w[res], [%[ptr]]" - : [res] "=&r" (result) - : [ptr] "r" (p) - : "memory"); - return result; -} +template<> +struct OrderAccess::PlatformOrderedLoad<1, X_ACQUIRE> + VALUE_OBJ_CLASS_SPEC +{ + template + T operator()(const volatile T* p) const { + volatile T result; + __asm__ volatile( + "ldarb %w[res], [%[ptr]]" + : [res] "=&r" (result) + : [ptr] "r" (p) + : "memory"); + return result; + } +}; -template<> inline jshort OrderAccess::specialized_load_acquire(const volatile jshort* p) { - volatile jshort result; - __asm__ volatile( - "ldarh %w[res], [%[ptr]]" - : [res] "=&r" (result) - : [ptr] "r" (p) - : "memory"); - return result; -} +template<> +struct OrderAccess::PlatformOrderedLoad<2, X_ACQUIRE> + VALUE_OBJ_CLASS_SPEC +{ + template + T operator()(const volatile T* p) const { + volatile T result; + __asm__ volatile( + "ldarh %w[res], [%[ptr]]" + : [res] "=&r" (result) + : [ptr] "r" (p) + : "memory"); + return result; + } +}; -template<> inline jint OrderAccess::specialized_load_acquire(const volatile jint* p) { - volatile jint result; - __asm__ volatile( - "ldar %w[res], [%[ptr]]" - : [res] "=&r" (result) - : [ptr] "r" (p) - : "memory"); - return result; -} +template<> +struct OrderAccess::PlatformOrderedLoad<4, X_ACQUIRE> + VALUE_OBJ_CLASS_SPEC +{ + template + T operator()(const volatile T* p) const { + volatile T result; + __asm__ volatile( + "ldar %w[res], [%[ptr]]" + : [res] "=&r" (result) + : [ptr] "r" (p) + : "memory"); + return result; + } +}; -template<> inline jfloat OrderAccess::specialized_load_acquire(const volatile jfloat* p) { - return jfloat_cast(specialized_load_acquire((const volatile jint*)p)); -} +template<> +struct OrderAccess::PlatformOrderedLoad<8, X_ACQUIRE> + VALUE_OBJ_CLASS_SPEC +{ + template + T operator()(const volatile T* p) const { + volatile T result; + __asm__ volatile( + "ldar %[res], [%[ptr]]" + : [res] "=&r" (result) + : [ptr] "r" (p) + : "memory"); + return result; + } +}; -// This is implicit as jlong and intptr_t are both "long int" -//template<> inline jlong OrderAccess::specialized_load_acquire(const volatile jlong* p) { -// return (volatile jlong)specialized_load_acquire((const volatile intptr_t*)p); -//} +template<> +struct OrderAccess::PlatformOrderedStore<1, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm__ volatile( + "stlrb %w[val], [%[ptr]]" + : + : [ptr] "r" (p), [val] "r" (v) + : "memory"); + } +}; -template<> inline intptr_t OrderAccess::specialized_load_acquire(const volatile intptr_t* p) { - volatile intptr_t result; - __asm__ volatile( - "ldar %[res], [%[ptr]]" - : [res] "=&r" (result) - : [ptr] "r" (p) - : "memory"); - return result; -} +template<> +struct OrderAccess::PlatformOrderedStore<2, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm__ volatile( + "stlrh %w[val], [%[ptr]]" + : + : [ptr] "r" (p), [val] "r" (v) + : "memory"); + } +}; -template<> inline jdouble OrderAccess::specialized_load_acquire(const volatile jdouble* p) { - return jdouble_cast(specialized_load_acquire((const volatile intptr_t*)p)); -} +template<> +struct OrderAccess::PlatformOrderedStore<4, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm__ volatile( + "stlr %w[val], [%[ptr]]" + : + : [ptr] "r" (p), [val] "r" (v) + : "memory"); + } +}; +template<> +struct OrderAccess::PlatformOrderedStore<8, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm__ volatile( + "stlr %[val], [%[ptr]]" + : + : [ptr] "r" (p), [val] "r" (v) + : "memory"); + } +}; -template<> inline void OrderAccess::specialized_release_store(volatile jbyte* p, jbyte v) { - __asm__ volatile( - "stlrb %w[val], [%[ptr]]" - : - : [ptr] "r" (p), [val] "r" (v) - : "memory"); -} - -template<> inline void OrderAccess::specialized_release_store(volatile jshort* p, jshort v) { - __asm__ volatile( - "stlrh %w[val], [%[ptr]]" - : - : [ptr] "r" (p), [val] "r" (v) - : "memory"); -} - -template<> inline void OrderAccess::specialized_release_store(volatile jint* p, jint v) { - __asm__ volatile( - "stlr %w[val], [%[ptr]]" - : - : [ptr] "r" (p), [val] "r" (v) - : "memory"); -} - -template<> inline void OrderAccess::specialized_release_store(volatile jlong* p, jlong v) { - __asm__ volatile( - "stlr %[val], [%[ptr]]" - : - : [ptr] "r" (p), [val] "r" (v) - : "memory"); -} #endif // AARCH64 #endif // OS_CPU_LINUX_ARM_VM_ORDERACCESS_LINUX_ARM_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp b/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp index a5a0f7d3124..764243960cc 100644 --- a/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp +++ b/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp @@ -32,22 +32,6 @@ // Implementation of class atomic -inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; } - -inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } - -inline jlong Atomic::load(const volatile jlong* src) { return *src; } - // // machine barrier instructions: // @@ -146,90 +130,14 @@ inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) co return result; } - -inline void Atomic::inc (volatile jint* dest) { - - unsigned int temp; - - __asm__ __volatile__ ( - strasm_nobarrier - "1: lwarx %0, 0, %2 \n" - " addic %0, %0, 1 \n" - " stwcx. %0, 0, %2 \n" - " bne- 1b \n" - strasm_nobarrier - : /*%0*/"=&r" (temp), "=m" (*dest) - : /*%2*/"r" (dest), "m" (*dest) - : "cc" strasm_nobarrier_clobber_memory); - -} - -inline void Atomic::inc_ptr(volatile intptr_t* dest) { - - long temp; - - __asm__ __volatile__ ( - strasm_nobarrier - "1: ldarx %0, 0, %2 \n" - " addic %0, %0, 1 \n" - " stdcx. %0, 0, %2 \n" - " bne- 1b \n" - strasm_nobarrier - : /*%0*/"=&r" (temp), "=m" (*dest) - : /*%2*/"r" (dest), "m" (*dest) - : "cc" strasm_nobarrier_clobber_memory); - -} - -inline void Atomic::inc_ptr(volatile void* dest) { - inc_ptr((volatile intptr_t*)dest); -} - - -inline void Atomic::dec (volatile jint* dest) { - - unsigned int temp; - - __asm__ __volatile__ ( - strasm_nobarrier - "1: lwarx %0, 0, %2 \n" - " addic %0, %0, -1 \n" - " stwcx. %0, 0, %2 \n" - " bne- 1b \n" - strasm_nobarrier - : /*%0*/"=&r" (temp), "=m" (*dest) - : /*%2*/"r" (dest), "m" (*dest) - : "cc" strasm_nobarrier_clobber_memory); - -} - -inline void Atomic::dec_ptr(volatile intptr_t* dest) { - - long temp; - - __asm__ __volatile__ ( - strasm_nobarrier - "1: ldarx %0, 0, %2 \n" - " addic %0, %0, -1 \n" - " stdcx. %0, 0, %2 \n" - " bne- 1b \n" - strasm_nobarrier - : /*%0*/"=&r" (temp), "=m" (*dest) - : /*%2*/"r" (dest), "m" (*dest) - : "cc" strasm_nobarrier_clobber_memory); - -} - -inline void Atomic::dec_ptr(volatile void* dest) { - dec_ptr((volatile intptr_t*)dest); -} - -inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) { - - // Note that xchg_ptr doesn't necessarily do an acquire +template<> +template +inline T Atomic::PlatformXchg<4>::operator()(T exchange_value, + T volatile* dest) const { + // Note that xchg doesn't necessarily do an acquire // (see synchronizer.cpp). - unsigned int old_value; + T old_value; const uint64_t zero = 0; __asm__ __volatile__ ( @@ -257,15 +165,18 @@ inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) { "memory" ); - return (jint) old_value; + return old_value; } -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { - - // Note that xchg_ptr doesn't necessarily do an acquire +template<> +template +inline T Atomic::PlatformXchg<8>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + // Note that xchg doesn't necessarily do an acquire // (see synchronizer.cpp). - long old_value; + T old_value; const uint64_t zero = 0; __asm__ __volatile__ ( @@ -293,11 +204,7 @@ inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* des "memory" ); - return (intptr_t) old_value; -} - -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); + return old_value; } inline void cmpxchg_pre_membar(cmpxchg_memory_order order) { diff --git a/src/hotspot/os_cpu/linux_ppc/orderAccess_linux_ppc.inline.hpp b/src/hotspot/os_cpu/linux_ppc/orderAccess_linux_ppc.inline.hpp index d41b788ab68..2f600407727 100644 --- a/src/hotspot/os_cpu/linux_ppc/orderAccess_linux_ppc.inline.hpp +++ b/src/hotspot/os_cpu/linux_ppc/orderAccess_linux_ppc.inline.hpp @@ -80,10 +80,14 @@ inline void OrderAccess::acquire() { inlasm_lwsync(); } inline void OrderAccess::release() { inlasm_lwsync(); } inline void OrderAccess::fence() { inlasm_sync(); } -template<> inline jbyte OrderAccess::specialized_load_acquire (const volatile jbyte* p) { register jbyte t = load(p); inlasm_acquire_reg(t); return t; } -template<> inline jshort OrderAccess::specialized_load_acquire(const volatile jshort* p) { register jshort t = load(p); inlasm_acquire_reg(t); return t; } -template<> inline jint OrderAccess::specialized_load_acquire (const volatile jint* p) { register jint t = load(p); inlasm_acquire_reg(t); return t; } -template<> inline jlong OrderAccess::specialized_load_acquire (const volatile jlong* p) { register jlong t = load(p); inlasm_acquire_reg(t); return t; } + +template +struct OrderAccess::PlatformOrderedLoad + VALUE_OBJ_CLASS_SPEC +{ + template + T operator()(const volatile T* p) const { register T t = Atomic::load(p); inlasm_acquire_reg(t); return t; } +}; #undef inlasm_sync #undef inlasm_lwsync @@ -91,6 +95,4 @@ template<> inline jlong OrderAccess::specialized_load_acquire (const vol #undef inlasm_isync #undef inlasm_acquire_reg -#define VM_HAS_GENERALIZED_ORDER_ACCESS 1 - #endif // OS_CPU_LINUX_PPC_VM_ORDERACCESS_LINUX_PPC_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_s390/atomic_linux_s390.hpp b/src/hotspot/os_cpu/linux_s390/atomic_linux_s390.hpp index e7c436bdd6e..5821bb018c3 100644 --- a/src/hotspot/os_cpu/linux_s390/atomic_linux_s390.hpp +++ b/src/hotspot/os_cpu/linux_s390/atomic_linux_s390.hpp @@ -53,20 +53,6 @@ // is an integer multiple of the data length. Furthermore, all stores are ordered: // a store which occurs conceptually before another store becomes visible to other CPUs // before the other store becomes visible. -inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; } - -inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } - //------------ // Atomic::add @@ -192,219 +178,6 @@ inline D Atomic::PlatformAdd<8>::add_and_fetch(I inc, D volatile* dest) const { } -//------------ -// Atomic::inc -//------------ -// These methods force the value in memory to be incremented (augmented by 1). -// Both, memory value and increment, are treated as 32bit signed binary integers. -// No overflow exceptions are recognized, and the condition code does not hold -// information about the value in memory. -// -// The value in memory is updated by using a compare-and-swap instruction. The -// instruction is retried as often as required. - -inline void Atomic::inc(volatile jint* dest) { - unsigned int old, upd; - - if (VM_Version::has_LoadAndALUAtomicV1()) { -// tty->print_cr("Atomic::inc called... dest @%p", dest); - __asm__ __volatile__ ( - " LGHI 2,1 \n\t" // load increment - " LA 3,%[mem] \n\t" // force data address into ARG2 -// " LAA %[upd],%[inc],%[mem] \n\t" // increment and get old value -// " LAA 2,2,0(3) \n\t" // actually coded instruction - " .byte 0xeb \n\t" // LAA main opcode - " .byte 0x22 \n\t" // R1,R3 - " .byte 0x30 \n\t" // R2,disp1 - " .byte 0x00 \n\t" // disp2,disp3 - " .byte 0x00 \n\t" // disp4,disp5 - " .byte 0xf8 \n\t" // LAA minor opcode - " AGHI 2,1 \n\t" // calc new value in register - " LR %[upd],2 \n\t" // move to result register - //---< outputs >--- - : [upd] "=&d" (upd) // write-only, updated counter value - , [mem] "+Q" (*dest) // read/write, memory to be updated atomically - //---< inputs >--- - : -// : [inc] "a" (inc) // read-only. - //---< clobbered >--- - : "cc", "r2", "r3", "memory" - ); - } else { - __asm__ __volatile__ ( - " LLGF %[old],%[mem] \n\t" // get old value - "0: LA %[upd],1(,%[old]) \n\t" // calc result - " CS %[old],%[upd],%[mem] \n\t" // try to xchg res with mem - " JNE 0b \n\t" // no success? -> retry - //---< outputs >--- - : [old] "=&a" (old) // write-only, old counter value - , [upd] "=&d" (upd) // write-only, updated counter value - , [mem] "+Q" (*dest) // read/write, memory to be updated atomically - //---< inputs >--- - : - //---< clobbered >--- - : "cc", "memory" - ); - } -} - -inline void Atomic::inc_ptr(volatile intptr_t* dest) { - unsigned long old, upd; - - if (VM_Version::has_LoadAndALUAtomicV1()) { - __asm__ __volatile__ ( - " LGHI 2,1 \n\t" // load increment - " LA 3,%[mem] \n\t" // force data address into ARG2 -// " LAAG %[upd],%[inc],%[mem] \n\t" // increment and get old value -// " LAAG 2,2,0(3) \n\t" // actually coded instruction - " .byte 0xeb \n\t" // LAA main opcode - " .byte 0x22 \n\t" // R1,R3 - " .byte 0x30 \n\t" // R2,disp1 - " .byte 0x00 \n\t" // disp2,disp3 - " .byte 0x00 \n\t" // disp4,disp5 - " .byte 0xe8 \n\t" // LAA minor opcode - " AGHI 2,1 \n\t" // calc new value in register - " LR %[upd],2 \n\t" // move to result register - //---< outputs >--- - : [upd] "=&d" (upd) // write-only, updated counter value - , [mem] "+Q" (*dest) // read/write, memory to be updated atomically - //---< inputs >--- - : -// : [inc] "a" (inc) // read-only. - //---< clobbered >--- - : "cc", "r2", "r3", "memory" - ); - } else { - __asm__ __volatile__ ( - " LG %[old],%[mem] \n\t" // get old value - "0: LA %[upd],1(,%[old]) \n\t" // calc result - " CSG %[old],%[upd],%[mem] \n\t" // try to xchg res with mem - " JNE 0b \n\t" // no success? -> retry - //---< outputs >--- - : [old] "=&a" (old) // write-only, old counter value - , [upd] "=&d" (upd) // write-only, updated counter value - , [mem] "+Q" (*dest) // read/write, memory to be updated atomically - //---< inputs >--- - : - //---< clobbered >--- - : "cc", "memory" - ); - } -} - -inline void Atomic::inc_ptr(volatile void* dest) { - inc_ptr((volatile intptr_t*)dest); -} - -//------------ -// Atomic::dec -//------------ -// These methods force the value in memory to be decremented (augmented by -1). -// Both, memory value and decrement, are treated as 32bit signed binary integers. -// No overflow exceptions are recognized, and the condition code does not hold -// information about the value in memory. -// -// The value in memory is updated by using a compare-and-swap instruction. The -// instruction is retried as often as required. - -inline void Atomic::dec(volatile jint* dest) { - unsigned int old, upd; - - if (VM_Version::has_LoadAndALUAtomicV1()) { - __asm__ __volatile__ ( - " LGHI 2,-1 \n\t" // load increment - " LA 3,%[mem] \n\t" // force data address into ARG2 -// " LAA %[upd],%[inc],%[mem] \n\t" // increment and get old value -// " LAA 2,2,0(3) \n\t" // actually coded instruction - " .byte 0xeb \n\t" // LAA main opcode - " .byte 0x22 \n\t" // R1,R3 - " .byte 0x30 \n\t" // R2,disp1 - " .byte 0x00 \n\t" // disp2,disp3 - " .byte 0x00 \n\t" // disp4,disp5 - " .byte 0xf8 \n\t" // LAA minor opcode - " AGHI 2,-1 \n\t" // calc new value in register - " LR %[upd],2 \n\t" // move to result register - //---< outputs >--- - : [upd] "=&d" (upd) // write-only, updated counter value - , [mem] "+Q" (*dest) // read/write, memory to be updated atomically - //---< inputs >--- - : -// : [inc] "a" (inc) // read-only. - //---< clobbered >--- - : "cc", "r2", "r3", "memory" - ); - } else { - __asm__ __volatile__ ( - " LLGF %[old],%[mem] \n\t" // get old value - // LAY not supported by inline assembler - // "0: LAY %[upd],-1(,%[old]) \n\t" // calc result - "0: LR %[upd],%[old] \n\t" // calc result - " AHI %[upd],-1 \n\t" - " CS %[old],%[upd],%[mem] \n\t" // try to xchg res with mem - " JNE 0b \n\t" // no success? -> retry - //---< outputs >--- - : [old] "=&a" (old) // write-only, old counter value - , [upd] "=&d" (upd) // write-only, updated counter value - , [mem] "+Q" (*dest) // read/write, memory to be updated atomically - //---< inputs >--- - : - //---< clobbered >--- - : "cc", "memory" - ); - } -} - -inline void Atomic::dec_ptr(volatile intptr_t* dest) { - unsigned long old, upd; - - if (VM_Version::has_LoadAndALUAtomicV1()) { - __asm__ __volatile__ ( - " LGHI 2,-1 \n\t" // load increment - " LA 3,%[mem] \n\t" // force data address into ARG2 -// " LAAG %[upd],%[inc],%[mem] \n\t" // increment and get old value -// " LAAG 2,2,0(3) \n\t" // actually coded instruction - " .byte 0xeb \n\t" // LAA main opcode - " .byte 0x22 \n\t" // R1,R3 - " .byte 0x30 \n\t" // R2,disp1 - " .byte 0x00 \n\t" // disp2,disp3 - " .byte 0x00 \n\t" // disp4,disp5 - " .byte 0xe8 \n\t" // LAA minor opcode - " AGHI 2,-1 \n\t" // calc new value in register - " LR %[upd],2 \n\t" // move to result register - //---< outputs >--- - : [upd] "=&d" (upd) // write-only, updated counter value - , [mem] "+Q" (*dest) // read/write, memory to be updated atomically - //---< inputs >--- - : -// : [inc] "a" (inc) // read-only. - //---< clobbered >--- - : "cc", "r2", "r3", "memory" - ); - } else { - __asm__ __volatile__ ( - " LG %[old],%[mem] \n\t" // get old value -// LAY not supported by inline assembler -// "0: LAY %[upd],-1(,%[old]) \n\t" // calc result - "0: LGR %[upd],%[old] \n\t" // calc result - " AGHI %[upd],-1 \n\t" - " CSG %[old],%[upd],%[mem] \n\t" // try to xchg res with mem - " JNE 0b \n\t" // no success? -> retry - //---< outputs >--- - : [old] "=&a" (old) // write-only, old counter value - , [upd] "=&d" (upd) // write-only, updated counter value - , [mem] "+Q" (*dest) // read/write, memory to be updated atomically - //---< inputs >--- - : - //---< clobbered >--- - : "cc", "memory" - ); - } -} - -inline void Atomic::dec_ptr(volatile void* dest) { - dec_ptr((volatile intptr_t*)dest); -} - //------------- // Atomic::xchg //------------- @@ -421,8 +194,12 @@ inline void Atomic::dec_ptr(volatile void* dest) { // // The return value is the (unchanged) value from memory as it was when the // replacement succeeded. -inline jint Atomic::xchg (jint xchg_val, volatile jint* dest) { - unsigned int old; +template<> +template +inline T Atomic::PlatformXchg<4>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(4 == sizeof(T)); + T old; __asm__ __volatile__ ( " LLGF %[old],%[mem] \n\t" // get old value @@ -432,16 +209,20 @@ inline jint Atomic::xchg (jint xchg_val, volatile jint* dest) { : [old] "=&d" (old) // write-only, prev value irrelevant , [mem] "+Q" (*dest) // read/write, memory to be updated atomically //---< inputs >--- - : [upd] "d" (xchg_val) // read-only, value to be written to memory + : [upd] "d" (exchange_value) // read-only, value to be written to memory //---< clobbered >--- : "cc", "memory" ); - return (jint)old; + return old; } -inline intptr_t Atomic::xchg_ptr(intptr_t xchg_val, volatile intptr_t* dest) { - unsigned long old; +template<> +template +inline T Atomic::PlatformXchg<8>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + T old; __asm__ __volatile__ ( " LG %[old],%[mem] \n\t" // get old value @@ -451,16 +232,12 @@ inline intptr_t Atomic::xchg_ptr(intptr_t xchg_val, volatile intptr_t* dest) { : [old] "=&d" (old) // write-only, init from memory , [mem] "+Q" (*dest) // read/write, memory to be updated atomically //---< inputs >--- - : [upd] "d" (xchg_val) // read-only, value to be written to memory + : [upd] "d" (exchange_value) // read-only, value to be written to memory //---< clobbered >--- : "cc", "memory" ); - return (intptr_t)old; -} - -inline void *Atomic::xchg_ptr(void *exchange_value, volatile void *dest) { - return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); + return old; } //---------------- @@ -544,6 +321,4 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T xchg_val, return old; } -inline jlong Atomic::load(const volatile jlong* src) { return *src; } - #endif // OS_CPU_LINUX_S390_VM_ATOMIC_LINUX_S390_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_s390/orderAccess_linux_s390.inline.hpp b/src/hotspot/os_cpu/linux_s390/orderAccess_linux_s390.inline.hpp index 2de7fb6a81f..89401f03553 100644 --- a/src/hotspot/os_cpu/linux_s390/orderAccess_linux_s390.inline.hpp +++ b/src/hotspot/os_cpu/linux_s390/orderAccess_linux_s390.inline.hpp @@ -74,10 +74,13 @@ inline void OrderAccess::acquire() { inlasm_zarch_acquire(); } inline void OrderAccess::release() { inlasm_zarch_release(); } inline void OrderAccess::fence() { inlasm_zarch_sync(); } -template<> inline jbyte OrderAccess::specialized_load_acquire (const volatile jbyte* p) { register jbyte t = *p; inlasm_zarch_acquire(); return t; } -template<> inline jshort OrderAccess::specialized_load_acquire(const volatile jshort* p) { register jshort t = *p; inlasm_zarch_acquire(); return t; } -template<> inline jint OrderAccess::specialized_load_acquire (const volatile jint* p) { register jint t = *p; inlasm_zarch_acquire(); return t; } -template<> inline jlong OrderAccess::specialized_load_acquire (const volatile jlong* p) { register jlong t = *p; inlasm_zarch_acquire(); return t; } +template +struct OrderAccess::PlatformOrderedLoad + VALUE_OBJ_CLASS_SPEC +{ + template + T operator()(const volatile T* p) const { register T t = *p; inlasm_zarch_acquire(); return t; } +}; #undef inlasm_compiler_barrier #undef inlasm_zarch_sync @@ -85,8 +88,4 @@ template<> inline jlong OrderAccess::specialized_load_acquire (const vol #undef inlasm_zarch_acquire #undef inlasm_zarch_fence -#define VM_HAS_GENERALIZED_ORDER_ACCESS 1 - #endif // OS_CPU_LINUX_S390_VM_ORDERACCESS_LINUX_S390_INLINE_HPP - - diff --git a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp index fa53de045d0..272c3e0f46b 100644 --- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 SAP SE. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017 SAP SE. 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 @@ -448,11 +448,17 @@ JVM_handle_linux_signal(int sig, } else { // thread->thread_state() != _thread_in_Java - if (sig == SIGILL && VM_Version::is_determine_features_test_running()) { - // SIGILL must be caused by VM_Version::determine_features(). + if ((sig == SIGILL) && VM_Version::is_determine_features_test_running()) { + // SIGILL must be caused by VM_Version::determine_features() + // when attempting to execute a non-existing instruction. //*(int *) (pc-6)=0; // Patch instruction to 0 to indicate that it causes a SIGILL. // Flushing of icache is not necessary. stub = pc; // Continue with next instruction. + } else if ((sig == SIGFPE) && VM_Version::is_determine_features_test_running()) { + // SIGFPE is known to be caused by trying to execute a vector instruction + // when the vector facility is installed, but operating system support is missing. + VM_Version::reset_has_VectorFacility(); + stub = pc; // Continue with next instruction. } else if (thread->thread_state() == _thread_in_vm && sig == SIGBUS && thread->doing_unsafe_access()) { // We don't really need a stub here! Just set the pending exeption and @@ -471,7 +477,7 @@ JVM_handle_linux_signal(int sig, // Info->si_addr need not be the exact address, it is only // guaranteed to be on the same page as the address that caused // the SIGSEGV. - if ((sig == SIGSEGV) && + if ((sig == SIGSEGV) && !UseMembar && (os::get_memory_serialize_page() == (address)((uintptr_t)info->si_addr & ~(os::vm_page_size()-1)))) { return true; @@ -510,7 +516,7 @@ JVM_handle_linux_signal(int sig, // Note: this should be combined with the trap_pc handling above, // because it handles the same issue. if (sig == SIGILL || sig == SIGFPE) { - pc = (address) info->si_addr; + pc = (address)info->si_addr; } VMError::report_and_die(t, sig, pc, info, ucVoid); diff --git a/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp index 3ea20f8789d..46a1268347a 100644 --- a/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp +++ b/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp @@ -27,30 +27,6 @@ // Implementation of class atomic -inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; } - -inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } - -inline void Atomic::inc (volatile jint* dest) { (void)add (1, dest); } -inline void Atomic::inc_ptr(volatile intptr_t* dest) { (void)add_ptr(1, dest); } -inline void Atomic::inc_ptr(volatile void* dest) { (void)add_ptr(1, dest); } - -inline void Atomic::dec (volatile jint* dest) { (void)add (-1, dest); } -inline void Atomic::dec_ptr(volatile intptr_t* dest) { (void)add_ptr(-1, dest); } -inline void Atomic::dec_ptr(volatile void* dest) { (void)add_ptr(-1, dest); } - -inline jlong Atomic::load(const volatile jlong* src) { return *src; } - template struct Atomic::PlatformAdd : Atomic::AddAndFetch > @@ -103,9 +79,12 @@ inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) co return rv; } - -inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) { - intptr_t rv = exchange_value; +template<> +template +inline T Atomic::PlatformXchg<4>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(4 == sizeof(T)); + T rv = exchange_value; __asm__ volatile( " swap [%2],%1\n\t" : "=r" (rv) @@ -114,8 +93,12 @@ inline jint Atomic::xchg (jint exchange_value, volatile jint* des return rv; } -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { - intptr_t rv = exchange_value; +template<> +template +inline T Atomic::PlatformXchg<8>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + T rv = exchange_value; __asm__ volatile( "1:\n\t" " mov %1, %%o3\n\t" @@ -131,10 +114,6 @@ inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* des return rv; } -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); -} - // No direct support for cmpxchg of bytes; emulate using int. template<> struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; diff --git a/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.inline.hpp b/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.inline.hpp index fd6078fcd31..c9fde925f7e 100644 --- a/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.inline.hpp +++ b/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -48,6 +48,4 @@ inline void OrderAccess::fence() { __asm__ volatile ("membar #StoreLoad" : : : "memory"); } -#define VM_HAS_GENERALIZED_ORDER_ACCESS 1 - #endif // OS_CPU_LINUX_SPARC_VM_ORDERACCESS_LINUX_SPARC_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp index f19bfa767a9..be5649dc401 100644 --- a/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp +++ b/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp @@ -27,19 +27,6 @@ // Implementation of class atomic -inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; } - -inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } - - template struct Atomic::PlatformAdd : Atomic::FetchAndAdd > @@ -61,25 +48,11 @@ inline D Atomic::PlatformAdd<4>::fetch_and_add(I add_value, D volatile* dest) co return old_value; } -inline void Atomic::inc (volatile jint* dest) { - __asm__ volatile ( "lock addl $1,(%0)" : - : "r" (dest) : "cc", "memory"); -} - -inline void Atomic::inc_ptr(volatile void* dest) { - inc_ptr((volatile intptr_t*)dest); -} - -inline void Atomic::dec (volatile jint* dest) { - __asm__ volatile ( "lock subl $1,(%0)" : - : "r" (dest) : "cc", "memory"); -} - -inline void Atomic::dec_ptr(volatile void* dest) { - dec_ptr((volatile intptr_t*)dest); -} - -inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) { +template<> +template +inline T Atomic::PlatformXchg<4>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(4 == sizeof(T)); __asm__ volatile ( "xchgl (%2),%0" : "=r" (exchange_value) : "0" (exchange_value), "r" (dest) @@ -87,10 +60,6 @@ inline jint Atomic::xchg (jint exchange_value, volatile jint* des return exchange_value; } -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); -} - template<> template inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, @@ -120,8 +89,6 @@ inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, } #ifdef AMD64 -inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } template<> template @@ -136,21 +103,11 @@ inline D Atomic::PlatformAdd<8>::fetch_and_add(I add_value, D volatile* dest) co return old_value; } -inline void Atomic::inc_ptr(volatile intptr_t* dest) { - __asm__ __volatile__ ("lock addq $1,(%0)" - : - : "r" (dest) - : "cc", "memory"); -} - -inline void Atomic::dec_ptr(volatile intptr_t* dest) { - __asm__ __volatile__ ("lock subq $1,(%0)" - : - : "r" (dest) - : "cc", "memory"); -} - -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { +template<> +template +inline T Atomic::PlatformXchg<8>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); __asm__ __volatile__ ("xchgq (%2),%0" : "=r" (exchange_value) : "0" (exchange_value), "r" (dest) @@ -172,22 +129,8 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, return exchange_value; } -inline jlong Atomic::load(const volatile jlong* src) { return *src; } - #else // !AMD64 -inline void Atomic::inc_ptr(volatile intptr_t* dest) { - inc((volatile jint*)dest); -} - -inline void Atomic::dec_ptr(volatile intptr_t* dest) { - dec((volatile jint*)dest); -} - -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { - return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest); -} - extern "C" { // defined in linux_x86.s jlong _Atomic_cmpxchg_long(jlong, volatile jlong*, jlong); @@ -204,18 +147,21 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, return cmpxchg_using_helper(_Atomic_cmpxchg_long, exchange_value, dest, compare_value); } -inline jlong Atomic::load(const volatile jlong* src) { +template<> +template +inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const { + STATIC_ASSERT(8 == sizeof(T)); volatile jlong dest; - _Atomic_move_long(src, &dest); - return dest; + _Atomic_move_long(reinterpret_cast(src), reinterpret_cast(&dest)); + return PrimitiveConversions::cast(dest); } -inline void Atomic::store(jlong store_value, jlong* dest) { - _Atomic_move_long((volatile jlong*)&store_value, (volatile jlong*)dest); -} - -inline void Atomic::store(jlong store_value, volatile jlong* dest) { - _Atomic_move_long((volatile jlong*)&store_value, dest); +template<> +template +inline void Atomic::PlatformStore<8>::operator()(T store_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + _Atomic_move_long(reinterpret_cast(&store_value), reinterpret_cast(dest)); } #endif // AMD64 diff --git a/src/hotspot/os_cpu/linux_x86/orderAccess_linux_x86.inline.hpp b/src/hotspot/os_cpu/linux_x86/orderAccess_linux_x86.inline.hpp index 0f564216e13..0d5585b6e70 100644 --- a/src/hotspot/os_cpu/linux_x86/orderAccess_linux_x86.inline.hpp +++ b/src/hotspot/os_cpu/linux_x86/orderAccess_linux_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -60,46 +60,57 @@ inline void OrderAccess::fence() { } template<> -inline void OrderAccess::specialized_release_store_fence (volatile jbyte* p, jbyte v) { - __asm__ volatile ( "xchgb (%2),%0" - : "=q" (v) - : "0" (v), "r" (p) - : "memory"); -} +struct OrderAccess::PlatformOrderedStore<1, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm__ volatile ( "xchgb (%2),%0" + : "=q" (v) + : "0" (v), "r" (p) + : "memory"); + } +}; + template<> -inline void OrderAccess::specialized_release_store_fence(volatile jshort* p, jshort v) { - __asm__ volatile ( "xchgw (%2),%0" - : "=r" (v) - : "0" (v), "r" (p) - : "memory"); -} +struct OrderAccess::PlatformOrderedStore<2, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm__ volatile ( "xchgw (%2),%0" + : "=r" (v) + : "0" (v), "r" (p) + : "memory"); + } +}; + template<> -inline void OrderAccess::specialized_release_store_fence (volatile jint* p, jint v) { - __asm__ volatile ( "xchgl (%2),%0" - : "=r" (v) - : "0" (v), "r" (p) - : "memory"); -} +struct OrderAccess::PlatformOrderedStore<4, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm__ volatile ( "xchgl (%2),%0" + : "=r" (v) + : "0" (v), "r" (p) + : "memory"); + } +}; #ifdef AMD64 template<> -inline void OrderAccess::specialized_release_store_fence (volatile jlong* p, jlong v) { - __asm__ volatile ( "xchgq (%2), %0" - : "=r" (v) - : "0" (v), "r" (p) - : "memory"); -} +struct OrderAccess::PlatformOrderedStore<8, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm__ volatile ( "xchgq (%2), %0" + : "=r" (v) + : "0" (v), "r" (p) + : "memory"); + } +}; #endif // AMD64 -template<> -inline void OrderAccess::specialized_release_store_fence (volatile jfloat* p, jfloat v) { - release_store_fence((volatile jint*)p, jint_cast(v)); -} -template<> -inline void OrderAccess::specialized_release_store_fence(volatile jdouble* p, jdouble v) { - release_store_fence((volatile jlong*)p, jlong_cast(v)); -} - -#define VM_HAS_GENERALIZED_ORDER_ACCESS 1 - #endif // OS_CPU_LINUX_X86_VM_ORDERACCESS_LINUX_X86_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp b/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp index 22af8a7fbb8..0713b6de460 100644 --- a/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp +++ b/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp @@ -87,7 +87,7 @@ static inline int m68k_add_and_fetch(int add_value, volatile int *ptr) { /* Atomically write VALUE into `*PTR' and returns the previous contents of `*PTR'. */ -static inline int m68k_lock_test_and_set(volatile int *ptr, int newval) { +static inline int m68k_lock_test_and_set(int newval, volatile int *ptr) { for (;;) { // Loop until success. int prev = *ptr; @@ -148,7 +148,7 @@ static inline int arm_add_and_fetch(int add_value, volatile int *ptr) { /* Atomically write VALUE into `*PTR' and returns the previous contents of `*PTR'. */ -static inline int arm_lock_test_and_set(volatile int *ptr, int newval) { +static inline int arm_lock_test_and_set(int newval, volatile int *ptr) { for (;;) { // Loop until a __kernel_cmpxchg succeeds. int prev = *ptr; @@ -159,14 +159,6 @@ static inline int arm_lock_test_and_set(volatile int *ptr, int newval) { } #endif // ARM -inline void Atomic::store(jint store_value, volatile jint* dest) { - *dest = store_value; -} - -inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { - *dest = store_value; -} - template struct Atomic::PlatformAdd : Atomic::AddAndFetch > @@ -201,42 +193,22 @@ inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) co return __sync_add_and_fetch(dest, add_value); } -inline void Atomic::inc(volatile jint* dest) { - add(1, dest); -} - -inline void Atomic::inc_ptr(volatile intptr_t* dest) { - add_ptr(1, dest); -} - -inline void Atomic::inc_ptr(volatile void* dest) { - add_ptr(1, dest); -} - -inline void Atomic::dec(volatile jint* dest) { - add(-1, dest); -} - -inline void Atomic::dec_ptr(volatile intptr_t* dest) { - add_ptr(-1, dest); -} - -inline void Atomic::dec_ptr(volatile void* dest) { - add_ptr(-1, dest); -} - -inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) { +template<> +template +inline T Atomic::PlatformXchg<4>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(4 == sizeof(T)); #ifdef ARM - return arm_lock_test_and_set(dest, exchange_value); + return xchg_using_helper(arm_lock_test_and_set, exchange_value, dest); #else #ifdef M68K - return m68k_lock_test_and_set(dest, exchange_value); + return xchg_using_helper(m68k_lock_test_and_set, exchange_value, dest); #else // __sync_lock_test_and_set is a bizarrely named atomic exchange // operation. Note that some platforms only support this with the // limitation that the only valid value to store is the immediate // constant 1. There is a test for this in JNI_CreateJavaVM(). - jint result = __sync_lock_test_and_set (dest, exchange_value); + T result = __sync_lock_test_and_set (dest, exchange_value); // All atomic operations are expected to be full memory barriers // (see atomic.hpp). However, __sync_lock_test_and_set is not // a full memory barrier, but an acquire barrier. Hence, this added @@ -247,24 +219,14 @@ inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) { #endif // ARM } -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, - volatile intptr_t* dest) { -#ifdef ARM - return arm_lock_test_and_set(dest, exchange_value); -#else -#ifdef M68K - return m68k_lock_test_and_set(dest, exchange_value); -#else - intptr_t result = __sync_lock_test_and_set (dest, exchange_value); +template<> +template +inline T Atomic::PlatformXchg<8>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + T result = __sync_lock_test_and_set (dest, exchange_value); __sync_synchronize(); return result; -#endif // M68K -#endif // ARM -} - -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void *) xchg_ptr((intptr_t) exchange_value, - (volatile intptr_t*) dest); } // No direct support for cmpxchg of bytes; emulate using int. @@ -299,18 +261,21 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, return __sync_val_compare_and_swap(dest, compare_value, exchange_value); } -inline jlong Atomic::load(const volatile jlong* src) { +template<> +template +inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const { + STATIC_ASSERT(8 == sizeof(T)); volatile jlong dest; - os::atomic_copy64(src, &dest); - return dest; + os::atomic_copy64(reinterpret_cast(src), reinterpret_cast(&dest)); + return PrimitiveConversions::cast(dest); } -inline void Atomic::store(jlong store_value, jlong* dest) { - os::atomic_copy64((volatile jlong*)&store_value, (volatile jlong*)dest); -} - -inline void Atomic::store(jlong store_value, volatile jlong* dest) { - os::atomic_copy64((volatile jlong*)&store_value, dest); +template<> +template +inline void Atomic::PlatformStore<8>::operator()(T store_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + os::atomic_copy64(reinterpret_cast(&store_value), reinterpret_cast(dest)); } #endif // OS_CPU_LINUX_ZERO_VM_ATOMIC_LINUX_ZERO_HPP diff --git a/src/hotspot/os_cpu/linux_zero/orderAccess_linux_zero.inline.hpp b/src/hotspot/os_cpu/linux_zero/orderAccess_linux_zero.inline.hpp index 20d851c9234..8c4cd1c7a1c 100644 --- a/src/hotspot/os_cpu/linux_zero/orderAccess_linux_zero.inline.hpp +++ b/src/hotspot/os_cpu/linux_zero/orderAccess_linux_zero.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -56,8 +56,16 @@ typedef void (__kernel_dmb_t) (void); #else // PPC +#ifdef ALPHA + +#define LIGHT_MEM_BARRIER __sync_synchronize() + +#else // ALPHA + #define LIGHT_MEM_BARRIER __asm __volatile ("":::"memory") +#endif // ALPHA + #endif // PPC #endif // ARM @@ -75,6 +83,4 @@ inline void OrderAccess::release() { LIGHT_MEM_BARRIER; } inline void OrderAccess::fence() { FULL_MEM_BARRIER; } -#define VM_HAS_GENERALIZED_ORDER_ACCESS 1 - #endif // OS_CPU_LINUX_ZERO_VM_ORDERACCESS_LINUX_ZERO_INLINE_HPP diff --git a/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp index 5314e931cf9..a8e00217da5 100644 --- a/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp +++ b/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp @@ -27,41 +27,6 @@ // Implementation of class atomic -inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; } - -inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } - -inline void Atomic::inc (volatile jint* dest) { (void)add (1, dest); } -inline void Atomic::inc_ptr(volatile intptr_t* dest) { (void)add_ptr(1, dest); } -inline void Atomic::inc_ptr(volatile void* dest) { (void)add_ptr(1, dest); } - -inline void Atomic::dec (volatile jint* dest) { (void)add (-1, dest); } -inline void Atomic::dec_ptr(volatile intptr_t* dest) { (void)add_ptr(-1, dest); } -inline void Atomic::dec_ptr(volatile void* dest) { (void)add_ptr(-1, dest); } - - -inline void Atomic::store(jlong store_value, jlong* dest) { *dest = store_value; } -inline void Atomic::store(jlong store_value, volatile jlong* dest) { *dest = store_value; } -inline jlong Atomic::load(const volatile jlong* src) { return *src; } - - -// This is the interface to the atomic instructions in solaris_sparc.il. -// It's very messy because we need to support v8 and these instructions -// are illegal there. When sparc v8 is dropped, we can drop out lots of -// this code. Also compiler2 does not support v8 so the conditional code -// omits the instruction set check. - -extern "C" jint _Atomic_swap32(jint exchange_value, volatile jint* dest); -extern "C" intptr_t _Atomic_swap64(intptr_t exchange_value, volatile intptr_t* dest); - // Implement ADD using a CAS loop. template struct Atomic::PlatformAdd VALUE_OBJ_CLASS_SPEC { @@ -78,16 +43,30 @@ struct Atomic::PlatformAdd VALUE_OBJ_CLASS_SPEC { } }; -inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) { - return _Atomic_swap32(exchange_value, dest); +template<> +template +inline T Atomic::PlatformXchg<4>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(4 == sizeof(T)); + __asm__ volatile ( "swap [%2],%0" + : "=r" (exchange_value) + : "0" (exchange_value), "r" (dest) + : "memory"); + return exchange_value; } -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { - return _Atomic_swap64(exchange_value, dest); -} - -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); +template<> +template +inline T Atomic::PlatformXchg<8>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + T old_value = *dest; + while (true) { + T result = cmpxchg(exchange_value, dest, old_value); + if (result == old_value) break; + old_value = result; + } + return old_value; } // No direct support for cmpxchg of bytes; emulate using int. diff --git a/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.inline.hpp b/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.inline.hpp index 7a74147d6a0..b60cd092c50 100644 --- a/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.inline.hpp +++ b/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -52,6 +52,4 @@ inline void OrderAccess::fence() { __asm__ volatile ("membar #StoreLoad" : : : "memory"); } -#define VM_HAS_GENERALIZED_ORDER_ACCESS 1 - #endif // OS_CPU_SOLARIS_SPARC_VM_ORDERACCESS_SOLARIS_SPARC_INLINE_HPP diff --git a/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il b/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il index 39ac68a7ec8..1f25542e5d5 100644 --- a/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il +++ b/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il @@ -32,47 +32,6 @@ .end - // Support for jint Atomic::xchg(jint exchange_value, volatile jint* dest). - // - // Arguments: - // exchange_value: O0 - // dest: O1 - // - // Results: - // O0: the value previously stored in dest - - .inline _Atomic_swap32, 2 - .volatile - swap [%o1],%o0 - .nonvolatile - .end - - - // Support for intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t * dest). - // - // 64-bit - // - // Arguments: - // exchange_value: O0 - // dest: O1 - // - // Results: - // O0: the value previously stored in dest - - .inline _Atomic_swap64, 2 - .volatile - 1: - mov %o0, %o3 - ldx [%o1], %o2 - casx [%o1], %o2, %o3 - cmp %o2, %o3 - bne %xcc, 1b - nop - mov %o2, %o0 - .nonvolatile - .end - - // Support for jlong Atomic::load and Atomic::store on v9. // // void _Atomic_move_long_v9(volatile jlong* src, volatile jlong* dst) diff --git a/src/hotspot/os_cpu/solaris_sparc/vm_version_solaris_sparc.cpp b/src/hotspot/os_cpu/solaris_sparc/vm_version_solaris_sparc.cpp index da767cbf642..7cbf60ee92a 100644 --- a/src/hotspot/os_cpu/solaris_sparc/vm_version_solaris_sparc.cpp +++ b/src/hotspot/os_cpu/solaris_sparc/vm_version_solaris_sparc.cpp @@ -380,7 +380,7 @@ void VM_Version::platform_features() { if (av & AV_SPARC_CRC32C) features |= ISA_crc32c_msk; #ifndef AV2_SPARC_FJATHPLUS -#define AV2_SPARC_FJATHPLUS 0x00000001 // Fujitsu Athena+ +#define AV2_SPARC_FJATHPLUS 0x00000001 // Fujitsu Athena+ insns #endif #ifndef AV2_SPARC_VIS3B #define AV2_SPARC_VIS3B 0x00000002 // VIS3 present on multiple chips @@ -405,6 +405,34 @@ void VM_Version::platform_features() { #endif #ifndef AV2_SPARC_VAMASK #define AV2_SPARC_VAMASK 0x00000100 // Virtual Address masking +#endif + +#ifndef AV2_SPARC_SPARC6 +#define AV2_SPARC_SPARC6 0x00000200 // REVB*, FPSLL*, RDENTROPY, LDM* and STM* +#endif +#ifndef AV2_SPARC_DICTUNP +#define AV2_SPARC_DICTUNP 0x00002000 // Dictionary unpack instruction +#endif +#ifndef AV2_SPARC_FPCMPSHL +#define AV2_SPARC_FPCMPSHL 0x00004000 // Partition compare with shifted result +#endif +#ifndef AV2_SPARC_RLE +#define AV2_SPARC_RLE 0x00008000 // Run-length encoded burst and length +#endif +#ifndef AV2_SPARC_SHA3 +#define AV2_SPARC_SHA3 0x00010000 // SHA3 instructions +#endif +#ifndef AV2_SPARC_FJATHPLUS2 +#define AV2_SPARC_FJATHPLUS2 0x00020000 // Fujitsu Athena++ insns +#endif +#ifndef AV2_SPARC_VIS3C +#define AV2_SPARC_VIS3C 0x00040000 // Subset of VIS3 insns provided by Athena++ +#endif +#ifndef AV2_SPARC_SPARC5B +#define AV2_SPARC_SPARC5B 0x00080000 // subset of SPARC5 insns (fpadd8, fpsub8) +#endif +#ifndef AV2_SPARC_MME +#define AV2_SPARC_MME 0x00100000 // Misaligned Mitigation Enable #endif if (avn > 1) { @@ -419,19 +447,30 @@ void VM_Version::platform_features() { if (av2 & AV2_SPARC_XMONT) features |= ISA_xmont_msk; if (av2 & AV2_SPARC_PAUSE_NSEC) features |= ISA_pause_nsec_msk; if (av2 & AV2_SPARC_VAMASK) features |= ISA_vamask_msk; + + if (av2 & AV2_SPARC_SPARC6) features |= ISA_sparc6_msk; + if (av2 & AV2_SPARC_DICTUNP) features |= ISA_dictunp_msk; + if (av2 & AV2_SPARC_FPCMPSHL) features |= ISA_fpcmpshl_msk; + if (av2 & AV2_SPARC_RLE) features |= ISA_rle_msk; + if (av2 & AV2_SPARC_SHA3) features |= ISA_sha3_msk; + if (av2 & AV2_SPARC_FJATHPLUS2) features |= ISA_fjathplus2_msk; + if (av2 & AV2_SPARC_VIS3C) features |= ISA_vis3c_msk; + if (av2 & AV2_SPARC_SPARC5B) features |= ISA_sparc5b_msk; + if (av2 & AV2_SPARC_MME) features |= ISA_mme_msk; } _features = features; // ISA feature set completed, update state. Sysinfo machine(SI_MACHINE); - bool is_sun4v = machine.match("sun4v"); // All Oracle SPARC + Fujitsu Athena+ + bool is_sun4v = machine.match("sun4v"); // All Oracle SPARC + Fujitsu Athena+/++ bool is_sun4u = machine.match("sun4u"); // All other Fujitsu - // Handle Athena+ conservatively (simply because we are lacking info.). + // Handle Athena+/++ conservatively (simply because we are lacking info.). - bool do_sun4v = is_sun4v && !has_athena_plus(); - bool do_sun4u = is_sun4u || has_athena_plus(); + bool an_athena = has_athena_plus() || has_athena_plus2(); + bool do_sun4v = is_sun4v && !an_athena; + bool do_sun4u = is_sun4u || an_athena; uint64_t synthetic = 0; @@ -441,16 +480,16 @@ void VM_Version::platform_features() { // Fast IDIV, BIS and LD available on Niagara Plus. if (has_vis2()) { synthetic |= (CPU_fast_idiv_msk | CPU_fast_ld_msk); - // ...on Core S4 however, we prefer not to use BIS. + // ...on Core C4 however, we prefer not to use BIS. if (!has_sparc5()) { synthetic |= CPU_fast_bis_msk; } } - // Niagara Core S3 supports fast RDPC and block zeroing. + // SPARC Core C3 supports fast RDPC and block zeroing. if (has_ima()) { synthetic |= (CPU_fast_rdpc_msk | CPU_blk_zeroing_msk); } - // Niagara Core S3 and S4 have slow CMOVE. + // SPARC Core C3 and C4 have slow CMOVE. if (!has_ima()) { synthetic |= CPU_fast_cmove_msk; } diff --git a/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp index c6919fbf38b..4acd7df025d 100644 --- a/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp +++ b/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp @@ -25,28 +25,6 @@ #ifndef OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP #define OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP -inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } - - -inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; } - -inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; } -inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } - -inline void Atomic::inc (volatile jint* dest) { (void)add (1, dest); } -inline void Atomic::inc_ptr(volatile intptr_t* dest) { (void)add_ptr(1, dest); } -inline void Atomic::inc_ptr(volatile void* dest) { (void)add_ptr(1, dest); } - -inline void Atomic::dec (volatile jint* dest) { (void)add (-1, dest); } -inline void Atomic::dec_ptr(volatile intptr_t* dest) { (void)add_ptr(-1, dest); } -inline void Atomic::dec_ptr(volatile void* dest) { (void)add_ptr(-1, dest); } - // For Sun Studio - implementation is in solaris_x86_64.il. extern "C" { @@ -92,8 +70,26 @@ inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) co reinterpret_cast(dest))); } -inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) { - return _Atomic_xchg(exchange_value, dest); +template<> +template +inline T Atomic::PlatformXchg<4>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(4 == sizeof(T)); + return PrimitiveConversions::cast( + _Atomic_xchg(PrimitiveConversions::cast(exchange_value), + reinterpret_cast(dest))); +} + +extern "C" jlong _Atomic_xchg_long(jlong exchange_value, volatile jlong* dest); + +template<> +template +inline T Atomic::PlatformXchg<8>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + return PrimitiveConversions::cast( + _Atomic_xchg_long(PrimitiveConversions::cast(exchange_value), + reinterpret_cast(dest))); } // Not using cmpxchg_using_helper here, because some configurations of @@ -141,18 +137,4 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, PrimitiveConversions::cast(compare_value))); } -inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } -extern "C" jlong _Atomic_xchg_long(jlong exchange_value, volatile jlong* dest); - -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { - return (intptr_t)_Atomic_xchg_long((jlong)exchange_value, (volatile jlong*)dest); -} - -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void*)_Atomic_xchg_long((jlong)exchange_value, (volatile jlong*)dest); -} - -inline jlong Atomic::load(const volatile jlong* src) { return *src; } - #endif // OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP diff --git a/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.inline.hpp b/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.inline.hpp index b88e715e4d4..bd676dbe62f 100644 --- a/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.inline.hpp +++ b/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -58,6 +58,4 @@ inline void OrderAccess::fence() { compiler_barrier(); } -#define VM_HAS_GENERALIZED_ORDER_ACCESS 1 - #endif // OS_CPU_SOLARIS_X86_VM_ORDERACCESS_SOLARIS_X86_INLINE_HPP diff --git a/src/hotspot/os_cpu/windows_x86/atomic_windows_x86.hpp b/src/hotspot/os_cpu/windows_x86/atomic_windows_x86.hpp index abf266917a1..5b72577fc6f 100644 --- a/src/hotspot/os_cpu/windows_x86/atomic_windows_x86.hpp +++ b/src/hotspot/os_cpu/windows_x86/atomic_windows_x86.hpp @@ -42,21 +42,6 @@ #pragma warning(disable: 4035) // Disables warnings reporting missing return statement -inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } - -inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; } - -inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; } -inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; } -inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; } - - -inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; } -inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } - template struct Atomic::PlatformAdd : Atomic::AddAndFetch > @@ -66,9 +51,6 @@ struct Atomic::PlatformAdd }; #ifdef AMD64 -inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } -inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } - template<> template inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { @@ -81,41 +63,19 @@ inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) co return add_using_helper(os::atomic_add_ptr_func, add_value, dest); } -inline void Atomic::inc (volatile jint* dest) { - (void)add (1, dest); -} +#define DEFINE_STUB_XCHG(ByteSize, StubType, StubName) \ + template<> \ + template \ + inline T Atomic::PlatformXchg::operator()(T exchange_value, \ + T volatile* dest) const { \ + STATIC_ASSERT(ByteSize == sizeof(T)); \ + return xchg_using_helper(StubName, exchange_value, dest); \ + } -inline void Atomic::inc_ptr(volatile intptr_t* dest) { - (void)add_ptr(1, dest); -} +DEFINE_STUB_XCHG(4, jint, os::atomic_xchg_func) +DEFINE_STUB_XCHG(8, jlong, os::atomic_xchg_long_func) -inline void Atomic::inc_ptr(volatile void* dest) { - (void)add_ptr(1, dest); -} - -inline void Atomic::dec (volatile jint* dest) { - (void)add (-1, dest); -} - -inline void Atomic::dec_ptr(volatile intptr_t* dest) { - (void)add_ptr(-1, dest); -} - -inline void Atomic::dec_ptr(volatile void* dest) { - (void)add_ptr(-1, dest); -} - -inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) { - return (jint)(*os::atomic_xchg_func)(exchange_value, dest); -} - -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { - return (intptr_t)(os::atomic_xchg_ptr_func)(exchange_value, dest); -} - -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void *)(os::atomic_xchg_ptr_func)((intptr_t)exchange_value, (volatile intptr_t*)dest); -} +#undef DEFINE_STUB_XCHG #define DEFINE_STUB_CMPXCHG(ByteSize, StubType, StubName) \ template<> \ @@ -134,8 +94,6 @@ DEFINE_STUB_CMPXCHG(8, jlong, os::atomic_cmpxchg_long_func) #undef DEFINE_STUB_CMPXCHG -inline jlong Atomic::load(const volatile jlong* src) { return *src; } - #else // !AMD64 template<> @@ -152,39 +110,11 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co } } -inline void Atomic::inc (volatile jint* dest) { - // alternative for InterlockedIncrement - __asm { - mov edx, dest; - lock add dword ptr [edx], 1; - } -} - -inline void Atomic::inc_ptr(volatile intptr_t* dest) { - inc((volatile jint*)dest); -} - -inline void Atomic::inc_ptr(volatile void* dest) { - inc((volatile jint*)dest); -} - -inline void Atomic::dec (volatile jint* dest) { - // alternative for InterlockedDecrement - __asm { - mov edx, dest; - lock sub dword ptr [edx], 1; - } -} - -inline void Atomic::dec_ptr(volatile intptr_t* dest) { - dec((volatile jint*)dest); -} - -inline void Atomic::dec_ptr(volatile void* dest) { - dec((volatile jint*)dest); -} - -inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) { +template<> +template +inline T Atomic::PlatformXchg<4>::operator()(T exchange_value, + T volatile* dest) const { + STATIC_ASSERT(4 == sizeof(T)); // alternative for InterlockedExchange __asm { mov eax, exchange_value; @@ -193,14 +123,6 @@ inline jint Atomic::xchg (jint exchange_value, volatile jint* des } } -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { - return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest); -} - -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void*)xchg((jint)exchange_value, (volatile jint*)dest); -} - template<> template inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, @@ -258,9 +180,12 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, } } -inline jlong Atomic::load(const volatile jlong* src) { - volatile jlong dest; - volatile jlong* pdest = &dest; +template<> +template +inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const { + STATIC_ASSERT(8 == sizeof(T)); + volatile T dest; + volatile T* pdest = &dest; __asm { mov eax, src fild qword ptr [eax] @@ -270,8 +195,12 @@ inline jlong Atomic::load(const volatile jlong* src) { return dest; } -inline void Atomic::store(jlong store_value, volatile jlong* dest) { - volatile jlong* src = &store_value; +template<> +template +inline void Atomic::PlatformStore<8>::operator()(T store_value, + T volatile* dest) const { + STATIC_ASSERT(8 == sizeof(T)); + volatile T* src = &store_value; __asm { mov eax, src fild qword ptr [eax] @@ -280,10 +209,6 @@ inline void Atomic::store(jlong store_value, volatile jlong* dest) { } } -inline void Atomic::store(jlong store_value, jlong* dest) { - Atomic::store(store_value, (volatile jlong*)dest); -} - #endif // AMD64 #pragma warning(default: 4035) // Enables warnings reporting missing return statement diff --git a/src/hotspot/os_cpu/windows_x86/orderAccess_windows_x86.inline.hpp b/src/hotspot/os_cpu/windows_x86/orderAccess_windows_x86.inline.hpp index 36c1c4a42c0..57488f4acf7 100644 --- a/src/hotspot/os_cpu/windows_x86/orderAccess_windows_x86.inline.hpp +++ b/src/hotspot/os_cpu/windows_x86/orderAccess_windows_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -74,42 +74,46 @@ inline void OrderAccess::fence() { #ifndef AMD64 template<> -inline void OrderAccess::specialized_release_store_fence (volatile jbyte* p, jbyte v) { - __asm { - mov edx, p; - mov al, v; - xchg al, byte ptr [edx]; +struct OrderAccess::PlatformOrderedStore<1, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm { + mov edx, p; + mov al, v; + xchg al, byte ptr [edx]; + } } -} +}; template<> -inline void OrderAccess::specialized_release_store_fence(volatile jshort* p, jshort v) { - __asm { - mov edx, p; - mov ax, v; - xchg ax, word ptr [edx]; +struct OrderAccess::PlatformOrderedStore<2, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm { + mov edx, p; + mov ax, v; + xchg ax, word ptr [edx]; + } } -} +}; template<> -inline void OrderAccess::specialized_release_store_fence (volatile jint* p, jint v) { - __asm { - mov edx, p; - mov eax, v; - xchg eax, dword ptr [edx]; +struct OrderAccess::PlatformOrderedStore<4, RELEASE_X_FENCE> + VALUE_OBJ_CLASS_SPEC +{ + template + void operator()(T v, volatile T* p) const { + __asm { + mov edx, p; + mov eax, v; + xchg eax, dword ptr [edx]; + } } -} +}; #endif // AMD64 -template<> -inline void OrderAccess::specialized_release_store_fence(volatile jfloat* p, jfloat v) { - release_store_fence((volatile jint*)p, jint_cast(v)); -} -template<> -inline void OrderAccess::specialized_release_store_fence(volatile jdouble* p, jdouble v) { - release_store_fence((volatile jlong*)p, jlong_cast(v)); -} - -#define VM_HAS_GENERALIZED_ORDER_ACCESS 1 - #endif // OS_CPU_WINDOWS_X86_VM_ORDERACCESS_WINDOWS_X86_INLINE_HPP diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp index d37dcff95b2..3dc70699bfc 100644 --- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp +++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp @@ -50,6 +50,7 @@ #include "runtime/stubRoutines.hpp" #include "runtime/thread.inline.hpp" #include "runtime/timer.hpp" +#include "symbolengine.hpp" #include "unwind_windows_x86.hpp" #include "utilities/events.hpp" #include "utilities/vmError.hpp" @@ -219,7 +220,7 @@ void os::initialize_thread(Thread* thr) { // Atomics and Stub Functions typedef jint xchg_func_t (jint, volatile jint*); -typedef intptr_t xchg_ptr_func_t (intptr_t, volatile intptr_t*); +typedef intptr_t xchg_long_func_t (jlong, volatile jlong*); typedef jint cmpxchg_func_t (jint, volatile jint*, jint); typedef jbyte cmpxchg_byte_func_t (jbyte, volatile jbyte*, jbyte); typedef jlong cmpxchg_long_func_t (jlong, volatile jlong*, jlong); @@ -243,12 +244,12 @@ jint os::atomic_xchg_bootstrap(jint exchange_value, volatile jint* dest) { return old_value; } -intptr_t os::atomic_xchg_ptr_bootstrap(intptr_t exchange_value, volatile intptr_t* dest) { +intptr_t os::atomic_xchg_long_bootstrap(jlong exchange_value, volatile jlong* dest) { // try to use the stub: - xchg_ptr_func_t* func = CAST_TO_FN_PTR(xchg_ptr_func_t*, StubRoutines::atomic_xchg_ptr_entry()); + xchg_long_func_t* func = CAST_TO_FN_PTR(xchg_long_func_t*, StubRoutines::atomic_xchg_long_entry()); if (func != NULL) { - os::atomic_xchg_ptr_func = func; + os::atomic_xchg_long_func = func; return (*func)(exchange_value, dest); } assert(Threads::number_of_threads() == 0, "for bootstrap only"); @@ -338,7 +339,7 @@ intptr_t os::atomic_add_ptr_bootstrap(intptr_t add_value, volatile intptr_t* des } xchg_func_t* os::atomic_xchg_func = os::atomic_xchg_bootstrap; -xchg_ptr_func_t* os::atomic_xchg_ptr_func = os::atomic_xchg_ptr_bootstrap; +xchg_long_func_t* os::atomic_xchg_long_func = os::atomic_xchg_long_bootstrap; cmpxchg_func_t* os::atomic_cmpxchg_func = os::atomic_cmpxchg_bootstrap; cmpxchg_byte_func_t* os::atomic_cmpxchg_byte_func = os::atomic_cmpxchg_byte_bootstrap; add_func_t* os::atomic_add_func = os::atomic_add_bootstrap; @@ -397,6 +398,12 @@ bool os::platform_print_native_stack(outputStream* st, const void* context, // may not contain what Java expects, and may cause the frame() constructor // to crash. Let's just print out the symbolic address. frame::print_C_frame(st, buf, buf_size, pc); + // print source file and line, if available + char buf[128]; + int line_no; + if (SymbolEngine::get_source_info(pc, buf, sizeof(buf), &line_no)) { + st->print(" (%s:%d)", buf, line_no); + } st->cr(); } lastpc = pc; diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.hpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.hpp index 306f983d6bd..495ad4ff071 100644 --- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.hpp +++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, 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 @@ -30,7 +30,7 @@ // #ifdef AMD64 static jint (*atomic_xchg_func) (jint, volatile jint*); - static intptr_t (*atomic_xchg_ptr_func) (intptr_t, volatile intptr_t*); + static intptr_t (*atomic_xchg_long_func) (jlong, volatile jlong*); static jint (*atomic_cmpxchg_func) (jint, volatile jint*, jint); static jbyte (*atomic_cmpxchg_byte_func) (jbyte, volatile jbyte*, jbyte); @@ -40,7 +40,7 @@ static intptr_t (*atomic_add_ptr_func) (intptr_t, volatile intptr_t*); static jint atomic_xchg_bootstrap (jint, volatile jint*); - static intptr_t atomic_xchg_ptr_bootstrap (intptr_t, volatile intptr_t*); + static intptr_t atomic_xchg_long_bootstrap (jlong, volatile jlong*); static jint atomic_cmpxchg_bootstrap (jint, volatile jint*, jint); static jbyte atomic_cmpxchg_byte_bootstrap(jbyte, volatile jbyte*, jbyte); diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp index 3e78d62e5d7..302e67bf5fb 100644 --- a/src/hotspot/share/adlc/output_c.cpp +++ b/src/hotspot/share/adlc/output_c.cpp @@ -2276,6 +2276,10 @@ private: if (strcmp(rep_var,"$XMMRegister") == 0) return "as_XMMRegister"; #endif if (strcmp(rep_var,"$CondRegister") == 0) return "as_ConditionRegister"; +#if defined(PPC64) + if (strcmp(rep_var,"$VectorRegister") == 0) return "as_VectorRegister"; + if (strcmp(rep_var,"$VectorSRegister") == 0) return "as_VectorSRegister"; +#endif return NULL; } diff --git a/src/hotspot/share/aot/aotCodeHeap.cpp b/src/hotspot/share/aot/aotCodeHeap.cpp index 15030057fdc..15c1e696ca4 100644 --- a/src/hotspot/share/aot/aotCodeHeap.cpp +++ b/src/hotspot/share/aot/aotCodeHeap.cpp @@ -60,7 +60,14 @@ Klass* AOTCodeHeap::get_klass_from_got(const char* klass_name, int klass_len, co fatal("Shared file %s error: klass %s should be resolved already", _lib->name(), klass_name); vm_exit(1); } + // Patch now to avoid extra runtime lookup _klasses_got[klass_data->_got_index] = k; + if (k->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(k); + if (ik->is_initialized()) { + _klasses_got[klass_data->_got_index - 1] = ik; + } + } } return k; } @@ -433,6 +440,7 @@ void AOTCodeHeap::link_shared_runtime_symbols() { SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_exception_handler_for_return_address", address, SharedRuntime::exception_handler_for_return_address); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_register_finalizer", address, SharedRuntime::register_finalizer); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_OSR_migration_end", address, SharedRuntime::OSR_migration_end); + SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_dynamic_invoke", address, CompilerRuntime::resolve_dynamic_invoke); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_string_by_symbol", address, CompilerRuntime::resolve_string_by_symbol); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_klass_by_symbol", address, CompilerRuntime::resolve_klass_by_symbol); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_method_by_symbol_and_load_counters", address, CompilerRuntime::resolve_method_by_symbol_and_load_counters); @@ -609,9 +617,13 @@ Method* AOTCodeHeap::find_method(Klass* klass, Thread* thread, const char* metho return m; } +AOTKlassData* AOTCodeHeap::find_klass(const char *name) { + return (AOTKlassData*) os::dll_lookup(_lib->dl_handle(), name); +} + AOTKlassData* AOTCodeHeap::find_klass(InstanceKlass* ik) { ResourceMark rm; - AOTKlassData* klass_data = (AOTKlassData*) os::dll_lookup(_lib->dl_handle(), ik->signature_name()); + AOTKlassData* klass_data = find_klass(ik->signature_name()); return klass_data; } @@ -640,35 +652,52 @@ bool AOTCodeHeap::is_dependent_method(Klass* dependee, AOTCompiledMethod* aot) { return false; } +void AOTCodeHeap::sweep_dependent_methods(int* indexes, int methods_cnt) { + int marked = 0; + for (int i = 0; i < methods_cnt; ++i) { + int code_id = indexes[i]; + // Invalidate aot code. + if (Atomic::cmpxchg(invalid, &_code_to_aot[code_id]._state, not_set) != not_set) { + if (_code_to_aot[code_id]._state == in_use) { + AOTCompiledMethod* aot = _code_to_aot[code_id]._aot; + assert(aot != NULL, "aot should be set"); + if (!aot->is_runtime_stub()) { // Something is wrong - should not invalidate stubs. + aot->mark_for_deoptimization(false); + marked++; + } + } + } + } + if (marked > 0) { + VM_Deoptimize op; + VMThread::execute(&op); + } +} + void AOTCodeHeap::sweep_dependent_methods(AOTKlassData* klass_data) { // Make dependent methods non_entrant forever. int methods_offset = klass_data->_dependent_methods_offset; if (methods_offset >= 0) { - int marked = 0; address methods_cnt_adr = _dependencies + methods_offset; int methods_cnt = *(int*)methods_cnt_adr; int* indexes = (int*)(methods_cnt_adr + 4); - for (int i = 0; i < methods_cnt; ++i) { - int code_id = indexes[i]; - // Invalidate aot code. - if (Atomic::cmpxchg(invalid, &_code_to_aot[code_id]._state, not_set) != not_set) { - if (_code_to_aot[code_id]._state == in_use) { - AOTCompiledMethod* aot = _code_to_aot[code_id]._aot; - assert(aot != NULL, "aot should be set"); - if (!aot->is_runtime_stub()) { // Something is wrong - should not invalidate stubs. - aot->mark_for_deoptimization(false); - marked++; - } - } - } - } - if (marked > 0) { - VM_Deoptimize op; - VMThread::execute(&op); - } + sweep_dependent_methods(indexes, methods_cnt); } } +void AOTCodeHeap::sweep_dependent_methods(InstanceKlass* ik) { + AOTKlassData* klass_data = find_klass(ik); + vmassert(klass_data != NULL, "dependency data missing"); + sweep_dependent_methods(klass_data); +} + +void AOTCodeHeap::sweep_method(AOTCompiledMethod *aot) { + int indexes[] = {aot->method_index()}; + sweep_dependent_methods(indexes, 1); + vmassert(aot->method()->code() != aot && aot->method()->aot_code() == NULL, "method still active"); +} + + bool AOTCodeHeap::load_klass_data(InstanceKlass* ik, Thread* thread) { ResourceMark rm; @@ -718,6 +747,9 @@ bool AOTCodeHeap::load_klass_data(InstanceKlass* ik, Thread* thread) { aot_class->_classloader = ik->class_loader_data(); // Set klass's Resolve (second) got cell. _klasses_got[klass_data->_got_index] = ik; + if (ik->is_initialized()) { + _klasses_got[klass_data->_got_index - 1] = ik; + } // Initialize global symbols of the DSO to the corresponding VM symbol values. link_global_lib_symbols(); @@ -837,7 +869,7 @@ void AOTCodeHeap::got_metadata_do(void f(Metadata*)) { f(md); } else { intptr_t meta = (intptr_t)md; - fatal("Invalid value in _metaspace_got[%d] = " INTPTR_FORMAT, i, meta); + fatal("Invalid value in _klasses_got[%d] = " INTPTR_FORMAT, i, meta); } } } @@ -886,6 +918,127 @@ void AOTCodeHeap::metadata_do(void f(Metadata*)) { aot->metadata_do(f); } } - // Scan metaspace_got cells. + // Scan klasses_got cells. got_metadata_do(f); } + +bool AOTCodeHeap::reconcile_dynamic_klass(AOTCompiledMethod *caller, InstanceKlass* holder, int index, Klass *dyno_klass, const char *descriptor1, const char *descriptor2) { + const char * const descriptors[2] = {descriptor1, descriptor2}; + JavaThread *thread = JavaThread::current(); + ResourceMark rm(thread); + + AOTKlassData* holder_data = find_klass(holder); + vmassert(holder_data != NULL, "klass %s not found", holder->signature_name()); + vmassert(is_dependent_method(holder, caller), "sanity"); + + AOTKlassData* dyno_data = NULL; + bool adapter_failed = false; + char buf[64]; + int descriptor_index = 0; + // descriptors[0] specific name ("adapter:") for matching + // descriptors[1] fall-back name ("adapter") for depdencies + while (descriptor_index < 2) { + const char *descriptor = descriptors[descriptor_index]; + if (descriptor == NULL) { + break; + } + jio_snprintf(buf, sizeof buf, "%s<%d:%d>", descriptor, holder_data->_class_id, index); + dyno_data = find_klass(buf); + if (dyno_data != NULL) { + break; + } + // If match failed then try fall-back for dependencies + ++descriptor_index; + adapter_failed = true; + } + + if (dyno_data == NULL && dyno_klass == NULL) { + // all is well, no (appendix) at compile-time, and still none + return true; + } + + if (dyno_data == NULL) { + // no (appendix) at build-time, but now there is + sweep_dependent_methods(holder_data); + return false; + } + + if (adapter_failed) { + // adapter method mismatch + sweep_dependent_methods(holder_data); + sweep_dependent_methods(dyno_data); + return false; + } + + if (dyno_klass == NULL) { + // (appendix) at build-time, none now + sweep_dependent_methods(holder_data); + sweep_dependent_methods(dyno_data); + return false; + } + + // TODO: support array appendix object + if (!dyno_klass->is_instance_klass()) { + sweep_dependent_methods(holder_data); + sweep_dependent_methods(dyno_data); + return false; + } + + InstanceKlass* dyno = InstanceKlass::cast(dyno_klass); + + if (!dyno->is_anonymous()) { + if (_klasses_got[dyno_data->_got_index] != dyno) { + // compile-time class different from runtime class, fail and deoptimize + sweep_dependent_methods(holder_data); + sweep_dependent_methods(dyno_data); + return false; + } + + if (dyno->is_initialized()) { + _klasses_got[dyno_data->_got_index - 1] = dyno; + } + return true; + } + + // TODO: support anonymous supers + if (!dyno->supers_have_passed_fingerprint_checks() || dyno->get_stored_fingerprint() != dyno_data->_fingerprint) { + NOT_PRODUCT( aot_klasses_fp_miss++; ) + log_trace(aot, class, fingerprint)("class %s%s has bad fingerprint in %s tid=" INTPTR_FORMAT, + dyno->internal_name(), dyno->is_shared() ? " (shared)" : "", + _lib->name(), p2i(thread)); + sweep_dependent_methods(holder_data); + sweep_dependent_methods(dyno_data); + return false; + } + + _klasses_got[dyno_data->_got_index] = dyno; + if (dyno->is_initialized()) { + _klasses_got[dyno_data->_got_index - 1] = dyno; + } + + // TODO: hook up any AOT code + // load_klass_data(dyno_data, thread); + return true; +} + +bool AOTCodeHeap::reconcile_dynamic_method(AOTCompiledMethod *caller, InstanceKlass* holder, int index, Method *adapter_method) { + InstanceKlass *adapter_klass = adapter_method->method_holder(); + char buf[64]; + jio_snprintf(buf, sizeof buf, "adapter:%d", adapter_method->method_idnum()); + if (!reconcile_dynamic_klass(caller, holder, index, adapter_klass, buf, "adapter")) { + return false; + } + return true; +} + +bool AOTCodeHeap::reconcile_dynamic_invoke(AOTCompiledMethod* caller, InstanceKlass* holder, int index, Method* adapter_method, Klass *appendix_klass) { + if (!reconcile_dynamic_klass(caller, holder, index, appendix_klass, "appendix")) { + return false; + } + + if (!reconcile_dynamic_method(caller, holder, index, adapter_method)) { + return false; + } + + return true; +} diff --git a/src/hotspot/share/aot/aotCodeHeap.hpp b/src/hotspot/share/aot/aotCodeHeap.hpp index 684f955c7b5..7bfd5c67531 100644 --- a/src/hotspot/share/aot/aotCodeHeap.hpp +++ b/src/hotspot/share/aot/aotCodeHeap.hpp @@ -241,13 +241,14 @@ public: AOTKlassData* find_klass(InstanceKlass* ik); bool load_klass_data(InstanceKlass* ik, Thread* thread); Klass* get_klass_from_got(const char* klass_name, int klass_len, const Method* method); - void sweep_dependent_methods(AOTKlassData* klass_data); + bool is_dependent_method(Klass* dependee, AOTCompiledMethod* aot); const char* get_name_at(int offset) { return _metaspace_names + offset; } + void oops_do(OopClosure* f); void metadata_do(void f(Metadata*)); void got_metadata_do(void f(Metadata*)); @@ -294,6 +295,21 @@ public: static void print_statistics(); #endif + + bool reconcile_dynamic_invoke(AOTCompiledMethod* caller, InstanceKlass* holder, int index, Method* adapter_method, Klass *appendix_klass); + +private: + AOTKlassData* find_klass(const char* name); + + void sweep_dependent_methods(int* indexes, int methods_cnt); + void sweep_dependent_methods(AOTKlassData* klass_data); + void sweep_dependent_methods(InstanceKlass* ik); + void sweep_method(AOTCompiledMethod* aot); + + bool reconcile_dynamic_klass(AOTCompiledMethod *caller, InstanceKlass* holder, int index, Klass *dyno, const char *descriptor1, const char *descriptor2 = NULL); + + bool reconcile_dynamic_method(AOTCompiledMethod *caller, InstanceKlass* holder, int index, Method *adapter_method); + }; #endif // SHARE_VM_AOT_AOTCODEHEAP_HPP diff --git a/src/hotspot/share/aot/aotLoader.cpp b/src/hotspot/share/aot/aotLoader.cpp index 5e1597d9b39..531a67f6e9e 100644 --- a/src/hotspot/share/aot/aotLoader.cpp +++ b/src/hotspot/share/aot/aotLoader.cpp @@ -40,6 +40,10 @@ GrowableArray* AOTLoader::_libraries = new(ResourceObj::C_HEAP, mtCode) #define FOR_ALL_AOT_LIBRARIES(lib) for (GrowableArrayIterator lib = libraries()->begin(); lib != libraries()->end(); ++lib) void AOTLoader::load_for_klass(InstanceKlass* ik, Thread* thread) { + if (ik->is_anonymous()) { + // don't even bother + return; + } if (UseAOT) { FOR_ALL_AOT_HEAPS(heap) { (*heap)->load_klass_data(ik, thread); @@ -48,6 +52,10 @@ void AOTLoader::load_for_klass(InstanceKlass* ik, Thread* thread) { } uint64_t AOTLoader::get_saved_fingerprint(InstanceKlass* ik) { + if (ik->is_anonymous()) { + // don't even bother + return 0; + } FOR_ALL_AOT_HEAPS(heap) { AOTKlassData* klass_data = (*heap)->find_klass(ik); if (klass_data != NULL) { @@ -259,3 +267,34 @@ void AOTLoader::print_statistics() { } } #endif + + +bool AOTLoader::reconcile_dynamic_invoke(InstanceKlass* holder, int index, Method* adapter_method, Klass* appendix_klass) { + if (!UseAOT) { + return true; + } + JavaThread* thread = JavaThread::current(); + ResourceMark rm(thread); + RegisterMap map(thread, false); + frame caller_frame = thread->last_frame().sender(&map); // Skip stub + CodeBlob* caller_cb = caller_frame.cb(); + guarantee(caller_cb != NULL && caller_cb->is_compiled(), "must be called from compiled method"); + CompiledMethod* cm = caller_cb->as_compiled_method(); + + if (!cm->is_aot()) { + return true; + } + AOTCompiledMethod* aot = (AOTCompiledMethod*)cm; + + AOTCodeHeap* caller_heap = NULL; + FOR_ALL_AOT_HEAPS(heap) { + if ((*heap)->contains_blob(aot)) { + caller_heap = *heap; + break; + } + } + guarantee(caller_heap != NULL, "CodeHeap not found"); + bool success = caller_heap->reconcile_dynamic_invoke(aot, holder, index, adapter_method, appendix_klass); + vmassert(success || thread->last_frame().sender(&map).is_deoptimized_frame(), "caller not deoptimized on failure"); + return success; +} diff --git a/src/hotspot/share/aot/aotLoader.hpp b/src/hotspot/share/aot/aotLoader.hpp index 01ff4102b62..87f745d46f0 100644 --- a/src/hotspot/share/aot/aotLoader.hpp +++ b/src/hotspot/share/aot/aotLoader.hpp @@ -28,6 +28,7 @@ #include "runtime/handles.hpp" class AOTCodeHeap; +class AOTCompiledMethod; class AOTLib; class CodeBlob; template class GrowableArray; @@ -71,6 +72,7 @@ public: static void flush_evol_dependents_on(InstanceKlass* dependee) NOT_AOT_RETURN; #endif // HOTSWAP + static bool reconcile_dynamic_invoke(InstanceKlass* holder, int index, Method* adapter_method, Klass *appendix_klass) NOT_AOT({ return true; }); }; #endif // SHARE_VM_AOT_AOTLOADER_HPP diff --git a/src/hotspot/share/asm/assembler.cpp b/src/hotspot/share/asm/assembler.cpp index 84fb55bb3ff..b685f750f69 100644 --- a/src/hotspot/share/asm/assembler.cpp +++ b/src/hotspot/share/asm/assembler.cpp @@ -236,11 +236,9 @@ DelayedConstant* DelayedConstant::add(BasicType type, if (dcon->match(type, cfn)) return dcon; if (dcon->value_fn == NULL) { - // (cmpxchg not because this is multi-threaded but because I'm paranoid) - if (Atomic::cmpxchg_ptr(CAST_FROM_FN_PTR(void*, cfn), &dcon->value_fn, NULL) == NULL) { + dcon->value_fn = cfn; dcon->type = type; return dcon; - } } } // If this assert is hit (in pre-integration testing!) then re-evaluate diff --git a/src/hotspot/share/c1/c1_Compilation.cpp b/src/hotspot/share/c1/c1_Compilation.cpp index 156e73014db..fd1902b13d8 100644 --- a/src/hotspot/share/c1/c1_Compilation.cpp +++ b/src/hotspot/share/c1/c1_Compilation.cpp @@ -500,18 +500,22 @@ void Compilation::generate_exception_handler_table() { scope_depths->trunc_to(0); pcos->trunc_to(0); + int prev_scope = 0; for (int i = 0; i < handlers->length(); i++) { XHandler* handler = handlers->handler_at(i); assert(handler->entry_pco() != -1, "must have been generated"); + assert(handler->scope_count() >= prev_scope, "handlers should be sorted by scope"); - int e = bcis->find(handler->handler_bci()); - if (e >= 0 && scope_depths->at(e) == handler->scope_count()) { - // two different handlers are declared to dispatch to the same - // catch bci. During parsing we created edges for each - // handler but we really only need one. The exception handler - // table will also get unhappy if we try to declare both since - // it's nonsensical. Just skip this handler. - continue; + if (handler->scope_count() == prev_scope) { + int e = bcis->find_from_end(handler->handler_bci()); + if (e >= 0 && scope_depths->at(e) == handler->scope_count()) { + // two different handlers are declared to dispatch to the same + // catch bci. During parsing we created edges for each + // handler but we really only need one. The exception handler + // table will also get unhappy if we try to declare both since + // it's nonsensical. Just skip this handler. + continue; + } } bcis->append(handler->handler_bci()); @@ -521,13 +525,14 @@ void Compilation::generate_exception_handler_table() { scope_depths->append(0); } else { scope_depths->append(handler->scope_count()); - } + } pcos->append(handler->entry_pco()); // stop processing once we hit a catch any if (handler->is_catch_all()) { assert(i == handlers->length() - 1, "catch all must be last handler"); - } + } + prev_scope = handler->scope_count(); } exception_handler_table()->add_subtable(info->pco(), bcis, scope_depths, pcos); } diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp index a9c073d32b0..757c5e79274 100644 --- a/src/hotspot/share/c1/c1_LIR.hpp +++ b/src/hotspot/share/c1/c1_LIR.hpp @@ -1913,6 +1913,12 @@ class LIR_OpProfileCall : public LIR_Op { virtual void emit_code(LIR_Assembler* masm); virtual LIR_OpProfileCall* as_OpProfileCall() { return this; } virtual void print_instr(outputStream* out) const PRODUCT_RETURN; + bool should_profile_receiver_type() const { + bool callee_is_static = _profiled_callee->is_loaded() && _profiled_callee->is_static(); + Bytecodes::Code bc = _profiled_method->java_code_at_bci(_profiled_bci); + bool call_is_virtual = (bc == Bytecodes::_invokevirtual && !_profiled_callee->can_be_statically_bound()) || bc == Bytecodes::_invokeinterface; + return C1ProfileVirtualCalls && call_is_virtual && !callee_is_static; + } }; // LIR_OpProfileType diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index 37bd62a6929..ed64f686a92 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -1304,7 +1304,9 @@ void LIRGenerator::do_getClass(Intrinsic* x) { // FIXME T_ADDRESS should actually be T_METADATA but it can't because the // meaning of these two is mixed up (see JDK-8026837). __ move(new LIR_Address(rcvr.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), temp, info); - __ move_wide(new LIR_Address(temp, in_bytes(Klass::java_mirror_offset()), T_OBJECT), result); + __ move_wide(new LIR_Address(temp, in_bytes(Klass::java_mirror_offset()), T_ADDRESS), result); + // mirror = ((OopHandle)mirror)->resolve(); + __ move_wide(new LIR_Address(result, T_OBJECT), result); } // java.lang.Class::isPrimitive() diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index c66a69dd689..e1d502bd5b9 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -1221,11 +1221,6 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i MutexLockerEx ml_code (CodeCache_lock, Mutex::_no_safepoint_check_flag); nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); guarantee(nm != NULL, "only nmethods can contain non-perm oops"); - if (!nm->on_scavenge_root_list() && - ((mirror.not_null() && mirror()->is_scavengable()) || - (appendix.not_null() && appendix->is_scavengable()))) { - CodeCache::add_scavenge_root_nmethod(nm); - } // Since we've patched some oops in the nmethod, // (re)register it with the heap. @@ -1377,8 +1372,6 @@ template int obj_arraycopy_work(oopDesc* src, T* src_addr, // barrier. The assert will fail if this is not the case. // Note that we use the non-virtual inlineable variant of write_ref_array. BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt"); - assert(bs->has_write_ref_array_pre_opt(), "For pre-barrier as well."); if (src == dst) { // same object, no check bs->write_ref_array_pre(dst_addr, length); diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 0c0e9e4e27b..bfde1da61b8 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -1218,12 +1218,12 @@ void ciEnv::dump_compile_data(outputStream* out) { method->signature()->as_quoted_ascii(), entry_bci, comp_level); if (compiler_data() != NULL) { - if (is_c2_compile(comp_level)) { // C2 or Shark + if (is_c2_compile(comp_level)) { #ifdef COMPILER2 // Dump C2 inlining data. ((Compile*)compiler_data())->dump_inline_data(out); #endif - } else if (is_c1_compile(comp_level)) { // C1 + } else if (is_c1_compile(comp_level)) { #ifdef COMPILER1 // Dump C1 inlining data. ((Compilation*)compiler_data())->dump_inline_data(out); diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp index e0b910cc2d3..00f4a3f14dd 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.cpp +++ b/src/hotspot/share/ci/ciInstanceKlass.cpp @@ -665,9 +665,8 @@ class StaticFinalFieldPrinter : public FieldClosure { _out->print_cr("null"); } else if (value->is_instance()) { if (value->is_a(SystemDictionary::String_klass())) { - _out->print("\""); - _out->print_raw(java_lang_String::as_quoted_ascii(value)); - _out->print_cr("\""); + const char* ascii_value = java_lang_String::as_quoted_ascii(value); + _out->print("\"%s\"", (ascii_value != NULL) ? ascii_value : ""); } else { const char* klass_name = value->klass()->name()->as_quoted_ascii(); _out->print_cr("%s", klass_name); diff --git a/src/hotspot/share/ci/ciMethod.cpp b/src/hotspot/share/ci/ciMethod.cpp index a960f17db52..d878fa93bab 100644 --- a/src/hotspot/share/ci/ciMethod.cpp +++ b/src/hotspot/share/ci/ciMethod.cpp @@ -53,10 +53,6 @@ #include "ci/ciTypeFlow.hpp" #include "oops/method.hpp" #endif -#ifdef SHARK -#include "ci/ciTypeFlow.hpp" -#include "oops/method.hpp" -#endif // ciMethod // @@ -97,10 +93,10 @@ ciMethod::ciMethod(const methodHandle& h_m, ciInstanceKlass* holder) : _exception_handlers = NULL; _liveness = NULL; _method_blocks = NULL; -#if defined(COMPILER2) || defined(SHARK) +#if defined(COMPILER2) _flow = NULL; _bcea = NULL; -#endif // COMPILER2 || SHARK +#endif // COMPILER2 ciEnv *env = CURRENT_ENV; if (env->jvmti_can_hotswap_or_post_breakpoint() && can_be_compiled()) { @@ -173,12 +169,12 @@ ciMethod::ciMethod(ciInstanceKlass* holder, _can_be_statically_bound(false), _method_blocks( NULL), _method_data( NULL) -#if defined(COMPILER2) || defined(SHARK) +#if defined(COMPILER2) , _flow( NULL), _bcea( NULL), _instructions_size(-1) -#endif // COMPILER2 || SHARK +#endif // COMPILER2 { // Usually holder and accessor are the same type but in some cases // the holder has the wrong class loader (e.g. invokedynamic call @@ -287,23 +283,6 @@ int ciMethod::vtable_index() { } -#ifdef SHARK -// ------------------------------------------------------------------ -// ciMethod::itable_index -// -// Get the position of this method's entry in the itable, if any. -int ciMethod::itable_index() { - check_is_loaded(); - assert(holder()->is_linked(), "must be linked"); - VM_ENTRY_MARK; - Method* m = get_Method(); - if (!m->has_itable_index()) - return Method::nonvirtual_vtable_index; - return m->itable_index(); -} -#endif // SHARK - - // ------------------------------------------------------------------ // ciMethod::native_entry // @@ -369,34 +348,34 @@ bool ciMethod::has_balanced_monitors() { // ------------------------------------------------------------------ // ciMethod::get_flow_analysis ciTypeFlow* ciMethod::get_flow_analysis() { -#if defined(COMPILER2) || defined(SHARK) +#if defined(COMPILER2) if (_flow == NULL) { ciEnv* env = CURRENT_ENV; _flow = new (env->arena()) ciTypeFlow(env, this); _flow->do_flow(); } return _flow; -#else // COMPILER2 || SHARK +#else // COMPILER2 ShouldNotReachHere(); return NULL; -#endif // COMPILER2 || SHARK +#endif // COMPILER2 } // ------------------------------------------------------------------ // ciMethod::get_osr_flow_analysis ciTypeFlow* ciMethod::get_osr_flow_analysis(int osr_bci) { -#if defined(COMPILER2) || defined(SHARK) +#if defined(COMPILER2) // OSR entry points are always place after a call bytecode of some sort assert(osr_bci >= 0, "must supply valid OSR entry point"); ciEnv* env = CURRENT_ENV; ciTypeFlow* flow = new (env->arena()) ciTypeFlow(env, this, osr_bci); flow->do_flow(); return flow; -#else // COMPILER2 || SHARK +#else // COMPILER2 ShouldNotReachHere(); return NULL; -#endif // COMPILER2 || SHARK +#endif // COMPILER2 } // ------------------------------------------------------------------ diff --git a/src/hotspot/share/ci/ciMethod.hpp b/src/hotspot/share/ci/ciMethod.hpp index 2d55771f131..bc77829a163 100644 --- a/src/hotspot/share/ci/ciMethod.hpp +++ b/src/hotspot/share/ci/ciMethod.hpp @@ -96,7 +96,7 @@ class ciMethod : public ciMetadata { // Optional liveness analyzer. MethodLiveness* _liveness; -#if defined(COMPILER2) || defined(SHARK) +#if defined(COMPILER2) ciTypeFlow* _flow; BCEscapeAnalyzer* _bcea; #endif @@ -216,9 +216,6 @@ class ciMethod : public ciMetadata { // Runtime information. int vtable_index(); -#ifdef SHARK - int itable_index(); -#endif // SHARK address native_entry(); address interpreter_entry(); diff --git a/src/hotspot/share/ci/ciTypeFlow.hpp b/src/hotspot/share/ci/ciTypeFlow.hpp index 381fff86a14..f9ffaafb93e 100644 --- a/src/hotspot/share/ci/ciTypeFlow.hpp +++ b/src/hotspot/share/ci/ciTypeFlow.hpp @@ -30,12 +30,6 @@ #include "ci/ciKlass.hpp" #include "ci/ciMethodBlocks.hpp" #endif -#ifdef SHARK -#include "ci/ciEnv.hpp" -#include "ci/ciKlass.hpp" -#include "ci/ciMethodBlocks.hpp" -#include "shark/shark_globals.hpp" -#endif class ciTypeFlow : public ResourceObj { diff --git a/src/hotspot/share/classfile/altHashing.hpp b/src/hotspot/share/classfile/altHashing.hpp index 43af02f39ce..15c6a34b25a 100644 --- a/src/hotspot/share/classfile/altHashing.hpp +++ b/src/hotspot/share/classfile/altHashing.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_VM_CLASSFILE_ALTHASHING_HPP #define SHARE_VM_CLASSFILE_ALTHASHING_HPP -#include "prims/jni.h" +#include "jni.h" #include "classfile/symbolTable.hpp" /** diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 369dd26f04c..73ab562145e 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -5924,20 +5924,31 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream, #if INCLUDE_CDS if (DumpLoadedClassList != NULL && stream->source() != NULL && classlist_file->is_open()) { - // Only dump the classes that can be stored into CDS archive. - // Anonymous classes such as generated LambdaForm classes are also not included. - if (SystemDictionaryShared::is_sharing_possible(_loader_data) && + if (!ClassLoader::has_jrt_entry()) { + warning("DumpLoadedClassList and CDS are not supported in exploded build"); + DumpLoadedClassList = NULL; + } else if (SystemDictionaryShared::is_sharing_possible(_loader_data) && _host_klass == NULL) { + // Only dump the classes that can be stored into CDS archive. + // Anonymous classes such as generated LambdaForm classes are also not included. oop class_loader = _loader_data->class_loader(); ResourceMark rm(THREAD); - // For the boot and platform class loaders, check if the class is not found in the - // java runtime image. Additional check for the boot class loader is if the class - // is not found in the boot loader's appended entries. This indicates that the class - // is not useable during run time, such as the ones found in the --patch-module entries, - // so it should not be included in the classlist file. - if (((class_loader == NULL && !ClassLoader::contains_append_entry(stream->source())) || - SystemDictionary::is_platform_class_loader(class_loader)) && - !ClassLoader::is_jrt(stream->source())) { + bool skip = false; + if (class_loader == NULL || SystemDictionary::is_platform_class_loader(class_loader)) { + // For the boot and platform class loaders, skip classes that are not found in the + // java runtime image, such as those found in the --patch-module entries. + // These classes can't be loaded from the archive during runtime. + if (!ClassLoader::is_modules_image(stream->source()) && strncmp(stream->source(), "jrt:", 4) != 0) { + skip = true; + } + + if (class_loader == NULL && ClassLoader::contains_append_entry(stream->source())) { + // .. but don't skip the boot classes that are loaded from -Xbootclasspath/a + // as they can be loaded from the archive during runtime. + skip = false; + } + } + if (skip) { tty->print_cr("skip writing class %s from source %s to classlist file", _class_name->as_C_string(), stream->source()); } else { diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index 8592616311f..56bfed2b268 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -578,8 +578,8 @@ void ClassPathImageEntry::compile_the_world(Handle loader, TRAPS) { } #endif -bool ClassPathImageEntry::is_jrt() { - return ClassLoader::is_jrt(name()); +bool ClassPathImageEntry::is_modules_image() const { + return ClassLoader::is_modules_image(name()); } #if INCLUDE_CDS @@ -795,14 +795,13 @@ void ClassLoader::setup_search_path(const char *class_path, bool bootstrap_searc // Check for a jimage if (Arguments::has_jimage()) { assert(_jrt_entry == NULL, "should not setup bootstrap class search path twice"); - assert(new_entry != NULL && new_entry->is_jrt(), "No java runtime image present"); + assert(new_entry != NULL && new_entry->is_modules_image(), "No java runtime image present"); _jrt_entry = new_entry; ++_num_entries; #if INCLUDE_CDS if (DumpSharedSpaces) { JImageFile *jimage = _jrt_entry->jimage(); assert(jimage != NULL, "No java runtime image file present"); - ClassLoader::initialize_module_loader_map(jimage); } #endif } @@ -1144,61 +1143,6 @@ int ClassLoader::crc32(int crc, const char* buf, int len) { return (*Crc32)(crc, (const jbyte*)buf, len); } -#if INCLUDE_CDS -void ClassLoader::initialize_module_loader_map(JImageFile* jimage) { - if (!DumpSharedSpaces) { - return; // only needed for CDS dump time - } - - ResourceMark rm; - jlong size; - JImageLocationRef location = (*JImageFindResource)(jimage, JAVA_BASE_NAME, get_jimage_version_string(), MODULE_LOADER_MAP, &size); - if (location == 0) { - vm_exit_during_initialization( - "Cannot find ModuleLoaderMap location from modules jimage.", NULL); - } - char* buffer = NEW_RESOURCE_ARRAY(char, size + 1); - buffer[size] = '\0'; - jlong read = (*JImageGetResource)(jimage, location, buffer, size); - if (read != size) { - vm_exit_during_initialization( - "Cannot find ModuleLoaderMap resource from modules jimage.", NULL); - } - char* char_buf = (char*)buffer; - int buflen = (int)strlen(char_buf); - char* begin_ptr = char_buf; - char* end_ptr = strchr(begin_ptr, '\n'); - bool process_boot_modules = false; - _boot_modules_array = new (ResourceObj::C_HEAP, mtModule) - GrowableArray(INITIAL_BOOT_MODULES_ARRAY_SIZE, true); - _platform_modules_array = new (ResourceObj::C_HEAP, mtModule) - GrowableArray(INITIAL_PLATFORM_MODULES_ARRAY_SIZE, true); - while (end_ptr != NULL && (end_ptr - char_buf) < buflen) { - // Allocate a buffer from the C heap to be appended to the _boot_modules_array - // or the _platform_modules_array. - char* temp_name = NEW_C_HEAP_ARRAY(char, (size_t)(end_ptr - begin_ptr + 1), mtInternal); - strncpy(temp_name, begin_ptr, end_ptr - begin_ptr); - temp_name[end_ptr - begin_ptr] = '\0'; - if (strncmp(temp_name, "BOOT", 4) == 0) { - process_boot_modules = true; - FREE_C_HEAP_ARRAY(char, temp_name); - } else if (strncmp(temp_name, "PLATFORM", 8) == 0) { - process_boot_modules = false; - FREE_C_HEAP_ARRAY(char, temp_name); - } else { - // module name - if (process_boot_modules) { - _boot_modules_array->append(temp_name); - } else { - _platform_modules_array->append(temp_name); - } - } - begin_ptr = ++end_ptr; - end_ptr = strchr(begin_ptr, '\n'); - } -} -#endif - // Function add_package extracts the package from the fully qualified class name // and checks if the package is in the boot loader's package entry table. If so, // then it sets the classpath_index in the package entry record. @@ -1290,58 +1234,6 @@ objArrayOop ClassLoader::get_system_packages(TRAPS) { return result(); } -#if INCLUDE_CDS -s2 ClassLoader::module_to_classloader(const char* module_name) { - - assert(DumpSharedSpaces, "dump time only"); - assert(_boot_modules_array != NULL, "_boot_modules_array is NULL"); - assert(_platform_modules_array != NULL, "_platform_modules_array is NULL"); - - int array_size = _boot_modules_array->length(); - for (int i = 0; i < array_size; i++) { - if (strcmp(module_name, _boot_modules_array->at(i)) == 0) { - return BOOT_LOADER; - } - } - - array_size = _platform_modules_array->length(); - for (int i = 0; i < array_size; i++) { - if (strcmp(module_name, _platform_modules_array->at(i)) == 0) { - return PLATFORM_LOADER; - } - } - - return APP_LOADER; -} - -s2 ClassLoader::classloader_type(Symbol* class_name, ClassPathEntry* e, int classpath_index, TRAPS) { - assert(DumpSharedSpaces, "Only used for CDS dump time"); - - // obtain the classloader type based on the class name. - // First obtain the package name based on the class name. Then obtain - // the classloader type based on the package name from the jimage using - // a jimage API. If the classloader type cannot be found from the - // jimage, it is determined by the class path entry. - jshort loader_type = ClassLoader::APP_LOADER; - if (e->is_jrt()) { - ResourceMark rm; - TempNewSymbol pkg_name = InstanceKlass::package_from_name(class_name, CHECK_0); - if (pkg_name != NULL) { - const char* pkg_name_C_string = (const char*)(pkg_name->as_C_string()); - ClassPathImageEntry* cpie = (ClassPathImageEntry*)e; - JImageFile* jimage = cpie->jimage(); - char* module_name = (char*)(*JImagePackageToModule)(jimage, pkg_name_C_string); - if (module_name != NULL) { - loader_type = ClassLoader::module_to_classloader(module_name); - } - } - } else if (ClassLoaderExt::is_boot_classpath(classpath_index)) { - loader_type = ClassLoader::BOOT_LOADER; - } - return loader_type; -} -#endif - // caller needs ResourceMark const char* ClassLoader::file_name_for_class_name(const char* class_name, int class_name_len) { @@ -1954,7 +1846,7 @@ void ClassLoader::compile_the_world() { // Iterate over all bootstrap class path appended entries ClassPathEntry* e = _first_append_entry; while (e != NULL) { - assert(!e->is_jrt(), "A modular java runtime image is present on the list of appended entries"); + assert(!e->is_modules_image(), "A modular java runtime image is present on the list of appended entries"); e->compile_the_world(system_class_loader, CATCH); e = e->next(); } diff --git a/src/hotspot/share/classfile/classLoader.hpp b/src/hotspot/share/classfile/classLoader.hpp index b5633962008..deb3d0ecc23 100644 --- a/src/hotspot/share/classfile/classLoader.hpp +++ b/src/hotspot/share/classfile/classLoader.hpp @@ -37,13 +37,6 @@ // Name of boot "modules" image #define MODULES_IMAGE_NAME "modules" -// Name of the resource containing mapping from module names to defining class loader type -#define MODULE_LOADER_MAP "jdk/internal/vm/cds/resources/ModuleLoaderMap.dat" - -// Initial sizes of the following arrays are based on the generated ModuleLoaderMap.dat -#define INITIAL_BOOT_MODULES_ARRAY_SIZE 30 -#define INITIAL_PLATFORM_MODULES_ARRAY_SIZE 15 - // Class path entry (directory or zip file) class JImageFile; @@ -55,15 +48,13 @@ private: ClassPathEntry* volatile _next; public: // Next entry in class path - ClassPathEntry* next() const { - return (ClassPathEntry*) OrderAccess::load_ptr_acquire(&_next); - } + ClassPathEntry* next() const { return OrderAccess::load_acquire(&_next); } virtual ~ClassPathEntry() {} void set_next(ClassPathEntry* next) { // may have unlocked readers, so ensure visibility. - OrderAccess::release_store_ptr(&_next, next); + OrderAccess::release_store(&_next, next); } - virtual bool is_jrt() = 0; + virtual bool is_modules_image() const = 0; virtual bool is_jar_file() const = 0; virtual const char* name() const = 0; virtual JImageFile* jimage() const = 0; @@ -80,7 +71,7 @@ class ClassPathDirEntry: public ClassPathEntry { private: const char* _dir; // Name of directory public: - bool is_jrt() { return false; } + bool is_modules_image() const { return false; } bool is_jar_file() const { return false; } const char* name() const { return _dir; } JImageFile* jimage() const { return NULL; } @@ -118,7 +109,7 @@ class ClassPathZipEntry: public ClassPathEntry { u1 _multi_versioned; // indicates if the jar file has multi-versioned entries. // It can have value of "_unknown", "_yes", or "_no" public: - bool is_jrt() { return false; } + bool is_modules_image() const { return false; } bool is_jar_file() const { return true; } const char* name() const { return _zip_name; } JImageFile* jimage() const { return NULL; } @@ -140,7 +131,7 @@ private: JImageFile* _jimage; const char* _name; public: - bool is_jrt(); + bool is_modules_image() const; bool is_jar_file() const { return false; } bool is_open() const { return _jimage != NULL; } const char* name() const { return _name == NULL ? "" : _name; } @@ -403,7 +394,8 @@ class ClassLoader: AllStatic { static int compute_Object_vtable(); static ClassPathEntry* classpath_entry(int n) { - assert(n >= 0 && n < _num_entries, "sanity"); + assert(n >= 0, "sanity"); + assert(!has_jrt_entry() || n < _num_entries, "sanity"); if (n == 0) { assert(has_jrt_entry(), "No class path entry at 0 for exploded module builds"); return ClassLoader::_jrt_entry; @@ -438,10 +430,6 @@ class ClassLoader: AllStatic { static bool check_shared_paths_misc_info(void* info, int size); static void exit_with_path_failure(const char* error, const char* message); - static s2 module_to_classloader(const char* module_name); - static void initialize_module_loader_map(JImageFile* jimage); - static s2 classloader_type(Symbol* class_name, ClassPathEntry* e, - int classpath_index, TRAPS); static void record_shared_class_loader_type(InstanceKlass* ik, const ClassFileStream* stream); #endif static JImageLocationRef jimage_find_resource(JImageFile* jf, const char* module_name, @@ -479,7 +467,7 @@ class ClassLoader: AllStatic { // distinguish from a class_name with no package name, as both cases have a NULL return value static const char* package_from_name(const char* const class_name, bool* bad_class_name = NULL); - static bool is_jrt(const char* name) { return string_ends_with(name, MODULES_IMAGE_NAME); } + static bool is_modules_image(const char* name) { return string_ends_with(name, MODULES_IMAGE_NAME); } // Debugging static void verify() PRODUCT_RETURN; diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index 8aaa0ee5044..761782bb35b 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -82,11 +82,6 @@ #include "trace/tracing.hpp" #endif -// helper function to avoid in-line casts -template static T* load_ptr_acquire(T* volatile *p) { - return static_cast(OrderAccess::load_ptr_acquire(p)); -} - ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL; ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) : @@ -98,7 +93,8 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen _keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0), _metaspace(NULL), _unloading(false), _klasses(NULL), _modules(NULL), _packages(NULL), - _claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL), + _claimed(0), _modified_oops(true), _accumulated_modified_oops(false), + _jmethod_ids(NULL), _handles(), _deallocate_list(NULL), _next(NULL), _dependencies(dependencies), _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true, Monitor::_safepoint_check_never)) { @@ -151,7 +147,7 @@ ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() { oop* ClassLoaderData::ChunkedHandleList::add(oop o) { if (_head == NULL || _head->_size == Chunk::CAPACITY) { Chunk* next = new Chunk(_head); - OrderAccess::release_store_ptr(&_head, next); + OrderAccess::release_store(&_head, next); } oop* handle = &_head->_data[_head->_size]; *handle = o; @@ -168,7 +164,7 @@ inline void ClassLoaderData::ChunkedHandleList::oops_do_chunk(OopClosure* f, Chu } void ClassLoaderData::ChunkedHandleList::oops_do(OopClosure* f) { - Chunk* head = (Chunk*) OrderAccess::load_ptr_acquire(&_head); + Chunk* head = OrderAccess::load_acquire(&_head); if (head != NULL) { // Must be careful when reading size of head oops_do_chunk(f, head, OrderAccess::load_acquire(&head->_size)); @@ -207,7 +203,7 @@ bool ClassLoaderData::ChunkedHandleList::contains(oop* p) { oops_do(&cl); return cl.found(); } -#endif +#endif // ASSERT bool ClassLoaderData::claim() { if (_claimed == 1) { @@ -236,19 +232,19 @@ void ClassLoaderData::dec_keep_alive() { } } -void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) { +void ClassLoaderData::oops_do(OopClosure* f, bool must_claim, bool clear_mod_oops) { if (must_claim && !claim()) { return; } + // Only clear modified_oops after the ClassLoaderData is claimed. + if (clear_mod_oops) { + clear_modified_oops(); + } + f->do_oop(&_class_loader); _dependencies.oops_do(f); - _handles.oops_do(f); - - if (klass_closure != NULL) { - classes_do(klass_closure); - } } void ClassLoaderData::Dependencies::oops_do(OopClosure* f) { @@ -256,24 +252,24 @@ void ClassLoaderData::Dependencies::oops_do(OopClosure* f) { } void ClassLoaderData::classes_do(KlassClosure* klass_closure) { - // Lock-free access requires load_ptr_acquire - for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) { + // Lock-free access requires load_acquire + for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { klass_closure->do_klass(k); assert(k != k->next_link(), "no loops!"); } } void ClassLoaderData::classes_do(void f(Klass * const)) { - // Lock-free access requires load_ptr_acquire - for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) { + // Lock-free access requires load_acquire + for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { f(k); assert(k != k->next_link(), "no loops!"); } } void ClassLoaderData::methods_do(void f(Method*)) { - // Lock-free access requires load_ptr_acquire - for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) { + // Lock-free access requires load_acquire + for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { if (k->is_instance_klass() && InstanceKlass::cast(k)->is_loaded()) { InstanceKlass::cast(k)->methods_do(f); } @@ -281,8 +277,8 @@ void ClassLoaderData::methods_do(void f(Method*)) { } void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) { - // Lock-free access requires load_ptr_acquire - for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) { + // Lock-free access requires load_acquire + for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { // Do not filter ArrayKlass oops here... if (k->is_array_klass() || (k->is_instance_klass() && InstanceKlass::cast(k)->is_loaded())) { klass_closure->do_klass(k); @@ -291,8 +287,8 @@ void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) { } void ClassLoaderData::classes_do(void f(InstanceKlass*)) { - // Lock-free access requires load_ptr_acquire - for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) { + // Lock-free access requires load_acquire + for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { if (k->is_instance_klass()) { f(InstanceKlass::cast(k)); } @@ -368,6 +364,9 @@ void ClassLoaderData::record_dependency(const Klass* k, TRAPS) { // Must handle over GC point. Handle dependency(THREAD, to); from_cld->_dependencies.add(dependency, CHECK); + + // Added a potentially young gen oop to the ClassLoaderData + record_modified_oops(); } @@ -445,7 +444,7 @@ void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) { k->set_next_link(old_value); // Link the new item into the list, making sure the linked class is stable // since the list can be walked without a lock - OrderAccess::release_store_ptr(&_klasses, k); + OrderAccess::release_store(&_klasses, k); } if (publicize && k->class_loader_data() != NULL) { @@ -585,8 +584,8 @@ void ClassLoaderData::unload() { ModuleEntryTable* ClassLoaderData::modules() { // Lazily create the module entry table at first request. - // Lock-free access requires load_ptr_acquire. - ModuleEntryTable* modules = load_ptr_acquire(&_modules); + // Lock-free access requires load_acquire. + ModuleEntryTable* modules = OrderAccess::load_acquire(&_modules); if (modules == NULL) { MutexLocker m1(Module_lock); // Check if _modules got allocated while we were waiting for this lock. @@ -596,7 +595,7 @@ ModuleEntryTable* ClassLoaderData::modules() { { MutexLockerEx m1(metaspace_lock(), Mutex::_no_safepoint_check_flag); // Ensure _modules is stable, since it is examined without a lock - OrderAccess::release_store_ptr(&_modules, modules); + OrderAccess::release_store(&_modules, modules); } } } @@ -733,8 +732,8 @@ Metaspace* ClassLoaderData::metaspace_non_null() { // to create smaller arena for Reflection class loaders also. // The reason for the delayed allocation is because some class loaders are // simply for delegating with no metadata of their own. - // Lock-free access requires load_ptr_acquire. - Metaspace* metaspace = load_ptr_acquire(&_metaspace); + // Lock-free access requires load_acquire. + Metaspace* metaspace = OrderAccess::load_acquire(&_metaspace); if (metaspace == NULL) { MutexLockerEx ml(_metaspace_lock, Mutex::_no_safepoint_check_flag); // Check if _metaspace got allocated while we were waiting for this lock. @@ -756,7 +755,7 @@ Metaspace* ClassLoaderData::metaspace_non_null() { metaspace = new Metaspace(_metaspace_lock, Metaspace::StandardMetaspaceType); } // Ensure _metaspace is stable, since it is examined without a lock - OrderAccess::release_store_ptr(&_metaspace, metaspace); + OrderAccess::release_store(&_metaspace, metaspace); } } return metaspace; @@ -764,6 +763,7 @@ Metaspace* ClassLoaderData::metaspace_non_null() { OopHandle ClassLoaderData::add_handle(Handle h) { MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); + record_modified_oops(); return OopHandle(_handles.add(h())); } @@ -875,8 +875,7 @@ void ClassLoaderData::dump(outputStream * const out) { if (Verbose) { Klass* k = _klasses; while (k != NULL) { - out->print_cr("klass " PTR_FORMAT ", %s, CT: %d, MUT: %d", k, k->name()->as_C_string(), - k->has_modified_oops(), k->has_accumulated_modified_oops()); + out->print_cr("klass " PTR_FORMAT ", %s", p2i(k), k->name()->as_C_string()); assert(k != k->next_link(), "no loops!"); k = k->next_link(); } @@ -910,8 +909,8 @@ void ClassLoaderData::verify() { } bool ClassLoaderData::contains_klass(Klass* klass) { - // Lock-free access requires load_ptr_acquire - for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) { + // Lock-free access requires load_acquire + for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { if (k == klass) return true; } return false; @@ -944,7 +943,7 @@ ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous, TRA if (!is_anonymous) { ClassLoaderData** cld_addr = java_lang_ClassLoader::loader_data_addr(loader()); // First, Atomically set it - ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL); + ClassLoaderData* old = Atomic::cmpxchg(cld, cld_addr, (ClassLoaderData*)NULL); if (old != NULL) { delete cld; // Returns the data. @@ -959,7 +958,7 @@ ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous, TRA do { cld->set_next(next); - ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next); + ClassLoaderData* exchanged = Atomic::cmpxchg(cld, list_head, next); if (exchanged == next) { LogTarget(Debug, class, loader, data) lt; if (lt.is_enabled()) { @@ -1003,25 +1002,25 @@ void ClassLoaderDataGraph::print_creation(outputStream* out, Handle loader, Clas } -void ClassLoaderDataGraph::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) { +void ClassLoaderDataGraph::oops_do(OopClosure* f, bool must_claim) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { - cld->oops_do(f, klass_closure, must_claim); + cld->oops_do(f, must_claim); } } -void ClassLoaderDataGraph::keep_alive_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) { +void ClassLoaderDataGraph::keep_alive_oops_do(OopClosure* f, bool must_claim) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { if (cld->keep_alive()) { - cld->oops_do(f, klass_closure, must_claim); + cld->oops_do(f, must_claim); } } } -void ClassLoaderDataGraph::always_strong_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) { +void ClassLoaderDataGraph::always_strong_oops_do(OopClosure* f, bool must_claim) { if (ClassUnloading) { - keep_alive_oops_do(f, klass_closure, must_claim); + keep_alive_oops_do(f, must_claim); } else { - oops_do(f, klass_closure, must_claim); + oops_do(f, must_claim); } } @@ -1383,7 +1382,7 @@ Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() { while (head != NULL) { Klass* next = next_klass_in_cldg(head); - Klass* old_head = (Klass*)Atomic::cmpxchg_ptr(next, &_next_klass, head); + Klass* old_head = Atomic::cmpxchg(next, &_next_klass, head); if (old_head == head) { return head; // Won the CAS. diff --git a/src/hotspot/share/classfile/classLoaderData.hpp b/src/hotspot/share/classfile/classLoaderData.hpp index 524c985dea2..7c912ba57bb 100644 --- a/src/hotspot/share/classfile/classLoaderData.hpp +++ b/src/hotspot/share/classfile/classLoaderData.hpp @@ -87,9 +87,9 @@ class ClassLoaderDataGraph : public AllStatic { static void purge(); static void clear_claimed_marks(); // oops do - static void oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim); - static void keep_alive_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim); - static void always_strong_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim); + static void oops_do(OopClosure* f, bool must_claim); + static void keep_alive_oops_do(OopClosure* blk, bool must_claim); + static void always_strong_oops_do(OopClosure* blk, bool must_claim); // cld do static void cld_do(CLDClosure* cl); static void cld_unloading_do(CLDClosure* cl); @@ -194,7 +194,7 @@ class ClassLoaderData : public CHeapObj { Chunk(Chunk* c) : _next(c), _size(0) { } }; - Chunk* _head; + Chunk* volatile _head; void oops_do_chunk(OopClosure* f, Chunk* c, const juint size); @@ -230,10 +230,16 @@ class ClassLoaderData : public CHeapObj { Mutex* _metaspace_lock; // Locks the metaspace for allocations and setup. bool _unloading; // true if this class loader goes away bool _is_anonymous; // if this CLD is for an anonymous class + + // Remembered sets support for the oops in the class loader data. + bool _modified_oops; // Card Table Equivalent (YC/CMS support) + bool _accumulated_modified_oops; // Mod Union Equivalent (CMS support) + s2 _keep_alive; // if this CLD is kept alive without a keep_alive_object(). // Used for anonymous classes and the boot class // loader. _keep_alive does not need to be volatile or // atomic since there is one unique CLD per anonymous class. + volatile int _claimed; // true if claimed, for example during GC traces. // To avoid applying oop closure more than once. // Has to be an int because we cas it. @@ -276,6 +282,19 @@ class ClassLoaderData : public CHeapObj { bool claimed() const { return _claimed == 1; } bool claim(); + // The CLD are not placed in the Heap, so the Card Table or + // the Mod Union Table can't be used to mark when CLD have modified oops. + // The CT and MUT bits saves this information for the whole class loader data. + void clear_modified_oops() { _modified_oops = false; } + public: + void record_modified_oops() { _modified_oops = true; } + bool has_modified_oops() { return _modified_oops; } + + void accumulate_modified_oops() { if (has_modified_oops()) _accumulated_modified_oops = true; } + void clear_accumulated_modified_oops() { _accumulated_modified_oops = false; } + bool has_accumulated_modified_oops() { return _accumulated_modified_oops; } + private: + void unload(); bool keep_alive() const { return _keep_alive > 0; } void classes_do(void f(Klass*)); @@ -346,8 +365,7 @@ class ClassLoaderData : public CHeapObj { inline unsigned int identity_hash() const { return (unsigned int)(((intptr_t)this) >> 3); } - // Used when tracing from klasses. - void oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim); + void oops_do(OopClosure* f, bool must_claim, bool clear_modified_oops = false); void classes_do(KlassClosure* klass_closure); Klass* klasses() { return _klasses; } diff --git a/src/hotspot/share/classfile/defaultMethods.cpp b/src/hotspot/share/classfile/defaultMethods.cpp index 596b567db49..b09d552bcf4 100644 --- a/src/hotspot/share/classfile/defaultMethods.cpp +++ b/src/hotspot/share/classfile/defaultMethods.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -767,15 +767,14 @@ static void create_default_methods( InstanceKlass* klass, // This is the guts of the default methods implementation. This is called just // after the classfile has been parsed if some ancestor has default methods. // -// First if finds any name/signature slots that need any implementation (either +// First it finds any name/signature slots that need any implementation (either // because they are miranda or a superclass's implementation is an overpass // itself). For each slot, iterate over the hierarchy, to see if they contain a // signature that matches the slot we are looking at. // -// For each slot filled, we generate an overpass method that either calls the -// unique default method candidate using invokespecial, or throws an exception -// (in the case of no default method candidates, or more than one valid -// candidate). These methods are then added to the class's method list. +// For each slot filled, we either record the default method candidate in the +// klass default_methods list or, only to handle exception cases, we create an +// overpass method that throws an exception and add it to the klass methods list. // The JVM does not create bridges nor handle generic signatures here. void DefaultMethods::generate_default_methods( InstanceKlass* klass, const GrowableArray* mirandas, TRAPS) { @@ -901,6 +900,11 @@ static void switchover_constant_pool(BytecodeConstantPool* bpool, // This allows virtual methods to override the overpass, but ensures // that a local method search will find the exception rather than an abstract // or default method that is not a valid candidate. +// +// Note that if overpass method are ever created that are not exception +// throwing methods then the loader constraint checking logic for vtable and +// itable creation needs to be changed to check loader constraints for the +// overpass methods that do not throw exceptions. static void create_defaults_and_exceptions( GrowableArray* slots, InstanceKlass* klass, TRAPS) { diff --git a/src/hotspot/share/classfile/dictionary.hpp b/src/hotspot/share/classfile/dictionary.hpp index 8b3099ab074..b2662a1b4c5 100644 --- a/src/hotspot/share/classfile/dictionary.hpp +++ b/src/hotspot/share/classfile/dictionary.hpp @@ -161,10 +161,10 @@ class DictionaryEntry : public HashtableEntry { void set_pd_set(ProtectionDomainEntry* new_head) { _pd_set = new_head; } ProtectionDomainEntry* pd_set_acquire() const { - return (ProtectionDomainEntry*)OrderAccess::load_ptr_acquire(&_pd_set); + return OrderAccess::load_acquire(&_pd_set); } void release_set_pd_set(ProtectionDomainEntry* new_head) { - OrderAccess::release_store_ptr(&_pd_set, new_head); + OrderAccess::release_store(&_pd_set, new_head); } // Tells whether the initiating class' protection domain can access the klass in this entry diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 26720f2b258..3499d3e9d01 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -889,7 +889,7 @@ void java_lang_Class::create_mirror(Klass* k, Handle class_loader, // Setup indirection from klass->mirror // after any exceptions can happen during allocations. - k->set_java_mirror(mirror()); + k->set_java_mirror(mirror); // Set the module field in the java_lang_Class instance. This must be done // after the mirror is set. diff --git a/src/hotspot/share/classfile/jimage.hpp b/src/hotspot/share/classfile/jimage.hpp index e2268e91510..298bc85d472 100644 --- a/src/hotspot/share/classfile/jimage.hpp +++ b/src/hotspot/share/classfile/jimage.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -22,7 +22,7 @@ * */ -#include "prims/jni.h" +#include "jni.h" // Opaque reference to a JImage file. class JImageFile; diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp index e16c6bd5490..3c687a45b1d 100644 --- a/src/hotspot/share/classfile/klassFactory.cpp +++ b/src/hotspot/share/classfile/klassFactory.cpp @@ -223,8 +223,8 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream, result->set_cached_class_file(cached_class_file); } - if (InstanceKlass::should_store_fingerprint()) { - result->store_fingerprint(!result->is_anonymous() ? stream->compute_fingerprint() : 0); + if (result->should_store_fingerprint()) { + result->store_fingerprint(stream->compute_fingerprint()); } TRACE_KLASS_CREATION(result, parser, THREAD); diff --git a/src/hotspot/share/classfile/moduleEntry.cpp b/src/hotspot/share/classfile/moduleEntry.cpp index 543800a2864..f12ff916e06 100644 --- a/src/hotspot/share/classfile/moduleEntry.cpp +++ b/src/hotspot/share/classfile/moduleEntry.cpp @@ -23,13 +23,13 @@ */ #include "precompiled.hpp" +#include "jni.h" #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.hpp" #include "classfile/moduleEntry.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "oops/symbol.hpp" -#include "prims/jni.h" #include "runtime/handles.inline.hpp" #include "runtime/safepoint.hpp" #include "trace/traceMacros.hpp" diff --git a/src/hotspot/share/classfile/moduleEntry.hpp b/src/hotspot/share/classfile/moduleEntry.hpp index 253f209b22c..b23dadd6f01 100644 --- a/src/hotspot/share/classfile/moduleEntry.hpp +++ b/src/hotspot/share/classfile/moduleEntry.hpp @@ -25,11 +25,11 @@ #ifndef SHARE_VM_CLASSFILE_MODULEENTRY_HPP #define SHARE_VM_CLASSFILE_MODULEENTRY_HPP +#include "jni.h" #include "classfile/classLoaderData.hpp" #include "classfile/vmSymbols.hpp" #include "oops/oopHandle.hpp" #include "oops/symbol.hpp" -#include "prims/jni.h" #include "runtime/jniHandles.hpp" #include "runtime/mutexLocker.hpp" #include "trace/traceMacros.hpp" diff --git a/src/hotspot/share/classfile/resolutionErrors.hpp b/src/hotspot/share/classfile/resolutionErrors.hpp index 866a4b122a3..bba235453a3 100644 --- a/src/hotspot/share/classfile/resolutionErrors.hpp +++ b/src/hotspot/share/classfile/resolutionErrors.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, 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 @@ -33,6 +33,12 @@ class ResolutionErrorEntry; // ResolutionError objects are used to record errors encountered during // constant pool resolution (JVMS 5.4.3). +// This value is added to the cpCache index of an invokedynamic instruction when +// storing the resolution error resulting from that invokedynamic instruction. +// This prevents issues where the cpCache index is the same as the constant pool +// index of another entry in the table. +const int CPCACHE_INDEX_MANGLE_VALUE = 1000000; + class ResolutionErrorTable : public Hashtable { public: @@ -73,6 +79,14 @@ public: // RedefineClasses support - remove obsolete constant pool entry void delete_entry(ConstantPool* c); + + // This function is used to encode an index to differentiate it from a + // constant pool index. It assumes it is being called with a cpCache index + // (that is less than 0). + static int encode_cpcache_index(int index) { + assert(index < 0, "Unexpected non-negative cpCache index"); + return index + CPCACHE_INDEX_MANGLE_VALUE; + } }; diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index ededdc3f2d0..22bf5b037e7 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -104,6 +104,7 @@ InstanceKlass* SystemDictionary::_well_known_klasses[SystemDictionary::WKID InstanceKlass* SystemDictionary::_box_klasses[T_VOID+1] = { NULL /*, NULL...*/ }; oop SystemDictionary::_java_system_loader = NULL; +oop SystemDictionary::_java_platform_loader = NULL; bool SystemDictionary::_has_loadClassInternal = false; bool SystemDictionary::_has_checkPackageAccess = false; @@ -117,27 +118,38 @@ const int defaultProtectionDomainCacheSize = 1009; // ---------------------------------------------------------------------------- -// Java-level SystemLoader +// Java-level SystemLoader and PlatformLoader oop SystemDictionary::java_system_loader() { return _java_system_loader; } -void SystemDictionary::compute_java_system_loader(TRAPS) { - Klass* system_klass = WK_KLASS(ClassLoader_klass); +oop SystemDictionary::java_platform_loader() { + return _java_platform_loader; +} + +void SystemDictionary::compute_java_loaders(TRAPS) { JavaValue result(T_OBJECT); + InstanceKlass* class_loader_klass = SystemDictionary::ClassLoader_klass(); JavaCalls::call_static(&result, - WK_KLASS(ClassLoader_klass), + class_loader_klass, vmSymbols::getSystemClassLoader_name(), vmSymbols::void_classloader_signature(), CHECK); _java_system_loader = (oop)result.get_jobject(); + JavaCalls::call_static(&result, + class_loader_klass, + vmSymbols::getPlatformClassLoader_name(), + vmSymbols::void_classloader_signature(), + CHECK); + + _java_platform_loader = (oop)result.get_jobject(); + CDS_ONLY(SystemDictionaryShared::initialize(CHECK);) } - ClassLoaderData* SystemDictionary::register_loader(Handle class_loader, TRAPS) { if (class_loader() == NULL) return ClassLoaderData::the_null_class_loader_data(); return ClassLoaderDataGraph::find_or_create(class_loader, THREAD); @@ -169,7 +181,7 @@ bool SystemDictionary::is_system_class_loader(oop class_loader) { return false; } return (class_loader->klass() == SystemDictionary::jdk_internal_loader_ClassLoaders_AppClassLoader_klass() || - class_loader == _java_system_loader); + class_loader == _java_system_loader); } // Returns true if the passed class loader is the platform class loader. @@ -1238,7 +1250,7 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name, SharedClassPathEntry* ent = (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index); if (!Universe::is_module_initialized()) { - assert(ent != NULL && ent->is_jrt(), + assert(ent != NULL && ent->is_modules_image(), "Loading non-bootstrap classes before the module system is initialized"); assert(class_loader.is_null(), "sanity"); return true; @@ -1274,7 +1286,7 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name, if (mod_entry != NULL) { // PackageEntry/ModuleEntry is found in the classloader. Check if the // ModuleEntry's location agrees with the archived class' origination. - if (ent->is_jrt() && mod_entry->location()->starts_with("jrt:")) { + if (ent->is_modules_image() && mod_entry->location()->starts_with("jrt:")) { return true; // Module class from the "module" jimage } } @@ -1285,7 +1297,7 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name, // 1. the class is from the unamed package // 2. or, the class is not from a module defined in the NULL classloader // 3. or, the class is from an unamed module - if (!ent->is_jrt() && ik->is_shared_boot_class()) { + if (!ent->is_modules_image() && ik->is_shared_boot_class()) { // the class is from the -Xbootclasspath/a if (pkg_string == NULL || pkg_entry == NULL || @@ -1940,6 +1952,7 @@ bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive, void SystemDictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) { strong->do_oop(&_java_system_loader); + strong->do_oop(&_java_platform_loader); strong->do_oop(&_system_loader_lock_obj); CDS_ONLY(SystemDictionaryShared::roots_oops_do(strong);) @@ -1964,6 +1977,7 @@ void SystemDictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) { void SystemDictionary::oops_do(OopClosure* f) { f->do_oop(&_java_system_loader); + f->do_oop(&_java_platform_loader); f->do_oop(&_system_loader_lock_obj); CDS_ONLY(SystemDictionaryShared::oops_do(f);) diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index 4bd30563527..17da32a2859 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -484,11 +484,14 @@ public: static bool Object_klass_loaded() { return WK_KLASS(Object_klass) != NULL; } static bool ClassLoader_klass_loaded() { return WK_KLASS(ClassLoader_klass) != NULL; } - // Returns default system loader + // Returns java system loader static oop java_system_loader(); - // Compute the default system loader - static void compute_java_system_loader(TRAPS); + // Returns java platform loader + static oop java_platform_loader(); + + // Compute the java system and platform loaders + static void compute_java_loaders(TRAPS); // Register a new class loader static ClassLoaderData* register_loader(Handle class_loader, TRAPS); @@ -700,6 +703,7 @@ protected: static InstanceKlass* _box_klasses[T_VOID+1]; static oop _java_system_loader; + static oop _java_platform_loader; static bool _has_loadClassInternal; static bool _has_checkPackageAccess; diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index 37daeb5547f..ef4a749ff58 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -69,14 +69,14 @@ static void* volatile _verify_byte_codes_fn = NULL; static volatile jint _is_new_verify_byte_codes_fn = (jint) true; static void* verify_byte_codes_fn() { - if (OrderAccess::load_ptr_acquire(&_verify_byte_codes_fn) == NULL) { + if (OrderAccess::load_acquire(&_verify_byte_codes_fn) == NULL) { void *lib_handle = os::native_java_library(); void *func = os::dll_lookup(lib_handle, "VerifyClassCodesForMajorVersion"); - OrderAccess::release_store_ptr(&_verify_byte_codes_fn, func); + OrderAccess::release_store(&_verify_byte_codes_fn, func); if (func == NULL) { _is_new_verify_byte_codes_fn = false; func = os::dll_lookup(lib_handle, "VerifyClassCodes"); - OrderAccess::release_store_ptr(&_verify_byte_codes_fn, func); + OrderAccess::release_store(&_verify_byte_codes_fn, func); } } return (void*)_verify_byte_codes_fn; diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 6bd7412cfb2..88f03e5a205 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -371,6 +371,7 @@ template(deadChild_name, "deadChild") \ template(getFromClass_name, "getFromClass") \ template(dispatch_name, "dispatch") \ + template(getPlatformClassLoader_name, "getPlatformClassLoader") \ template(getSystemClassLoader_name, "getSystemClassLoader") \ template(fillInStackTrace_name, "fillInStackTrace") \ template(getCause_name, "getCause") \ @@ -461,6 +462,8 @@ template(getProtectionDomain_signature, "(Ljava/security/CodeSource;)Ljava/security/ProtectionDomain;") \ template(url_code_signer_array_void_signature, "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \ template(module_entry_name, "module_entry") \ + template(resolved_references_name, "") \ + template(init_lock_name, "") \ \ /* name symbols needed by intrinsics */ \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, template, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) \ @@ -779,6 +782,7 @@ do_name(decrementExact_name,"decrementExact") \ do_name(incrementExact_name,"incrementExact") \ do_name(multiplyExact_name,"multiplyExact") \ + do_name(multiplyHigh_name,"multiplyHigh") \ do_name(negateExact_name,"negateExact") \ do_name(subtractExact_name,"subtractExact") \ do_name(fma_name, "fma") \ @@ -803,6 +807,7 @@ do_intrinsic(_incrementExactL, java_lang_Math, incrementExact_name, long_long_signature, F_S) \ do_intrinsic(_multiplyExactI, java_lang_Math, multiplyExact_name, int2_int_signature, F_S) \ do_intrinsic(_multiplyExactL, java_lang_Math, multiplyExact_name, long2_long_signature, F_S) \ + do_intrinsic(_multiplyHigh, java_lang_Math, multiplyHigh_name, long2_long_signature, F_S) \ do_intrinsic(_negateExactI, java_lang_Math, negateExact_name, int_int_signature, F_S) \ do_intrinsic(_negateExactL, java_lang_Math, negateExact_name, long_long_signature, F_S) \ do_intrinsic(_subtractExactI, java_lang_Math, subtractExact_name, int2_int_signature, F_S) \ diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 773352b1101..35b356b7d37 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -125,7 +125,6 @@ public: inline bool is_compiled_by_c1() const { return _type == compiler_c1; }; inline bool is_compiled_by_c2() const { return _type == compiler_c2; }; inline bool is_compiled_by_jvmci() const { return _type == compiler_jvmci; }; - inline bool is_compiled_by_shark() const { return _type == compiler_shark; }; const char* compiler_name() const; // Casting @@ -157,6 +156,13 @@ public: int relocation_size() const { return (address) relocation_end() - (address) relocation_begin(); } int content_size() const { return content_end() - content_begin(); } int code_size() const { return code_end() - code_begin(); } + // Only used from CodeCache::free_unused_tail() after the Interpreter blob was trimmed + void adjust_size(size_t used) { + _size = (int)used; + _data_offset = (int)used; + _code_end = (address)this + used; + _data_end = (address)this + used; + } // Containment bool blob_contains(address addr) const { return header_begin() <= addr && addr < data_end(); } diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index 56c230e3bbf..b49892b1bf0 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -569,6 +569,21 @@ void CodeCache::free(CodeBlob* cb) { assert(heap->blob_count() >= 0, "sanity check"); } +void CodeCache::free_unused_tail(CodeBlob* cb, size_t used) { + assert_locked_or_safepoint(CodeCache_lock); + guarantee(cb->is_buffer_blob() && strncmp("Interpreter", cb->name(), 11) == 0, "Only possible for interpreter!"); + print_trace("free_unused_tail", cb); + + // We also have to account for the extra space (i.e. header) used by the CodeBlob + // which provides the memory (see BufferBlob::create() in codeBlob.cpp). + used += CodeBlob::align_code_offset(cb->header_size()); + + // Get heap for given CodeBlob and deallocate its unused tail + get_code_heap(cb)->deallocate_tail(cb, used); + // Adjust the sizes of the CodeBlob + cb->adjust_size(used); +} + void CodeCache::commit(CodeBlob* cb) { // this is called by nmethod::nmethod, which must already own CodeCache_lock assert_locked_or_safepoint(CodeCache_lock); @@ -683,22 +698,19 @@ void CodeCache::blobs_do(CodeBlobClosure* f) { if (cb->is_alive()) { f->do_code_blob(cb); #ifdef ASSERT - if (cb->is_nmethod()) - ((nmethod*)cb)->verify_scavenge_root_oops(); + if (cb->is_nmethod()) { + Universe::heap()->verify_nmethod((nmethod*)cb); + } #endif //ASSERT } } } } -// Walk the list of methods which might contain non-perm oops. +// Walk the list of methods which might contain oops to the java heap. void CodeCache::scavenge_root_nmethods_do(CodeBlobToOopClosure* f) { assert_locked_or_safepoint(CodeCache_lock); - if (UseG1GC) { - return; - } - const bool fix_relocations = f->fix_relocations(); debug_only(mark_scavenge_root_nmethods()); @@ -735,13 +747,20 @@ void CodeCache::scavenge_root_nmethods_do(CodeBlobToOopClosure* f) { debug_only(verify_perm_nmethods(NULL)); } +void CodeCache::register_scavenge_root_nmethod(nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + if (!nm->on_scavenge_root_list() && nm->detect_scavenge_root_oops()) { + add_scavenge_root_nmethod(nm); + } +} + +void CodeCache::verify_scavenge_root_nmethod(nmethod* nm) { + nm->verify_scavenge_root_oops(); +} + void CodeCache::add_scavenge_root_nmethod(nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); - if (UseG1GC) { - return; - } - nm->set_on_scavenge_root_list(); nm->set_scavenge_root_link(_scavenge_root_nmethods); set_scavenge_root_nmethods(nm); @@ -754,8 +773,6 @@ void CodeCache::unlink_scavenge_root_nmethod(nmethod* nm, nmethod* prev) { assert((prev == NULL && scavenge_root_nmethods() == nm) || (prev != NULL && prev->scavenge_root_link() == nm), "precondition"); - assert(!UseG1GC, "G1 does not use the scavenge_root_nmethods list"); - print_trace("unlink_scavenge_root", nm); if (prev == NULL) { set_scavenge_root_nmethods(nm->scavenge_root_link()); @@ -769,10 +786,6 @@ void CodeCache::unlink_scavenge_root_nmethod(nmethod* nm, nmethod* prev) { void CodeCache::drop_scavenge_root_nmethod(nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); - if (UseG1GC) { - return; - } - print_trace("drop_scavenge_root", nm); nmethod* prev = NULL; for (nmethod* cur = scavenge_root_nmethods(); cur != NULL; cur = cur->scavenge_root_link()) { @@ -788,10 +801,6 @@ void CodeCache::drop_scavenge_root_nmethod(nmethod* nm) { void CodeCache::prune_scavenge_root_nmethods() { assert_locked_or_safepoint(CodeCache_lock); - if (UseG1GC) { - return; - } - debug_only(mark_scavenge_root_nmethods()); nmethod* last = NULL; @@ -820,10 +829,6 @@ void CodeCache::prune_scavenge_root_nmethods() { #ifndef PRODUCT void CodeCache::asserted_non_scavengable_nmethods_do(CodeBlobClosure* f) { - if (UseG1GC) { - return; - } - // While we are here, verify the integrity of the list. mark_scavenge_root_nmethods(); for (nmethod* cur = scavenge_root_nmethods(); cur != NULL; cur = cur->scavenge_root_link()) { @@ -833,7 +838,7 @@ void CodeCache::asserted_non_scavengable_nmethods_do(CodeBlobClosure* f) { verify_perm_nmethods(f); } -// Temporarily mark nmethods that are claimed to be on the non-perm list. +// Temporarily mark nmethods that are claimed to be on the scavenge list. void CodeCache::mark_scavenge_root_nmethods() { NMethodIterator iter; while(iter.next_alive()) { @@ -854,7 +859,7 @@ void CodeCache::verify_perm_nmethods(CodeBlobClosure* f_or_null) { assert(nm->scavenge_root_not_marked(), "must be already processed"); if (nm->on_scavenge_root_list()) call_f = false; // don't show this one to the client - nm->verify_scavenge_root_oops(); + Universe::heap()->verify_nmethod(nm); if (call_f) f_or_null->do_code_blob(nm); } } @@ -1640,4 +1645,3 @@ void CodeCache::log_state(outputStream* st) { blob_count(), nmethod_count(), adapter_count(), unallocated_capacity()); } - diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 37e63e7089c..2749acd05b7 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -143,6 +143,7 @@ class CodeCache : AllStatic { static int alignment_unit(); // guaranteed alignment of all CodeBlobs static int alignment_offset(); // guaranteed offset of first CodeBlob byte within alignment unit (i.e., allocation header) static void free(CodeBlob* cb); // frees a CodeBlob + static void free_unused_tail(CodeBlob* cb, size_t used); // frees the unused tail of a CodeBlob (only used by TemplateInterpreter::initialize()) static bool contains(void *p); // returns whether p is included static bool contains(nmethod* nm); // returns whether nm is included static void blobs_do(void f(CodeBlob* cb)); // iterates over all CodeBlobs @@ -181,6 +182,10 @@ class CodeCache : AllStatic { static void scavenge_root_nmethods_do(CodeBlobToOopClosure* f); static nmethod* scavenge_root_nmethods() { return _scavenge_root_nmethods; } + // register_scavenge_root_nmethod() conditionally adds the nmethod to the list + // if it is not already on the list and has a scavengeable root + static void register_scavenge_root_nmethod(nmethod* nm); + static void verify_scavenge_root_nmethod(nmethod* nm); static void add_scavenge_root_nmethod(nmethod* nm); static void drop_scavenge_root_nmethod(nmethod* nm); diff --git a/src/hotspot/share/code/compiledMethod.cpp b/src/hotspot/share/code/compiledMethod.cpp index 130c32f2138..07f7ac8ab74 100644 --- a/src/hotspot/share/code/compiledMethod.cpp +++ b/src/hotspot/share/code/compiledMethod.cpp @@ -294,7 +294,6 @@ int CompiledMethod::verify_icholder_relocations() { // Method that knows how to preserve outgoing arguments at call. This method must be // called with a frame corresponding to a Java invoke void CompiledMethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { -#ifndef SHARK if (method() != NULL && !method()->is_native()) { address pc = fr.pc(); SimpleScopeDesc ssd(this, pc); @@ -314,7 +313,6 @@ void CompiledMethod::preserve_callee_argument_oops(frame fr, const RegisterMap * fr.oops_compiled_arguments_do(signature, has_receiver, has_appendix, reg_map, f); } -#endif // !SHARK } Method* CompiledMethod::attached_method(address call_instr) { diff --git a/src/hotspot/share/code/compiledMethod.hpp b/src/hotspot/share/code/compiledMethod.hpp index 65f64469a0c..0c0bb37a42e 100644 --- a/src/hotspot/share/code/compiledMethod.hpp +++ b/src/hotspot/share/code/compiledMethod.hpp @@ -288,7 +288,7 @@ public: // Note: _exception_cache may be read concurrently. We rely on memory_order_consume here. ExceptionCache* exception_cache() const { return _exception_cache; } void set_exception_cache(ExceptionCache *ec) { _exception_cache = ec; } - void release_set_exception_cache(ExceptionCache *ec) { OrderAccess::release_store_ptr(&_exception_cache, ec); } + void release_set_exception_cache(ExceptionCache *ec) { OrderAccess::release_store(&_exception_cache, ec); } address handler_for_exception_and_pc(Handle exception, address pc); void add_handler_for_exception_and_pc(Handle exception, address pc, address handler); void clean_exception_cache(BoolObjectClosure* is_alive); diff --git a/src/hotspot/share/code/jvmticmlr.h b/src/hotspot/share/code/jvmticmlr.h deleted file mode 100644 index c2106d3a7dc..00000000000 --- a/src/hotspot/share/code/jvmticmlr.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2010, 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 header file defines the data structures sent by the VM - * through the JVMTI CompiledMethodLoad callback function via the - * "void * compile_info" parameter. The memory pointed to by the - * compile_info parameter may not be referenced after returning from - * the CompiledMethodLoad callback. These are VM implementation - * specific data structures that may evolve in future releases. A - * JVMTI agent should interpret a non-NULL compile_info as a pointer - * to a region of memory containing a list of records. In a typical - * usage scenario, a JVMTI agent would cast each record to a - * jvmtiCompiledMethodLoadRecordHeader, a struct that represents - * arbitrary information. This struct contains a kind field to indicate - * the kind of information being passed, and a pointer to the next - * record. If the kind field indicates inlining information, then the - * agent would cast the record to a jvmtiCompiledMethodLoadInlineRecord. - * This record contains an array of PCStackInfo structs, which indicate - * for every pc address what are the methods on the invocation stack. - * The "methods" and "bcis" fields in each PCStackInfo struct specify a - * 1-1 mapping between these inlined methods and their bytecode indices. - * This can be used to derive the proper source lines of the inlined - * methods. - */ - -#ifndef _JVMTI_CMLR_H_ -#define _JVMTI_CMLR_H_ - -enum { - JVMTI_CMLR_MAJOR_VERSION_1 = 0x00000001, - JVMTI_CMLR_MINOR_VERSION_0 = 0x00000000, - - JVMTI_CMLR_MAJOR_VERSION = 0x00000001, - JVMTI_CMLR_MINOR_VERSION = 0x00000000 - - /* - * This comment is for the "JDK import from HotSpot" sanity check: - * version: 1.0.0 - */ -}; - -typedef enum { - JVMTI_CMLR_DUMMY = 1, - JVMTI_CMLR_INLINE_INFO = 2 -} jvmtiCMLRKind; - -/* - * Record that represents arbitrary information passed through JVMTI - * CompiledMethodLoadEvent void pointer. - */ -typedef struct _jvmtiCompiledMethodLoadRecordHeader { - jvmtiCMLRKind kind; /* id for the kind of info passed in the record */ - jint majorinfoversion; /* major and minor info version values. Init'ed */ - jint minorinfoversion; /* to current version value in jvmtiExport.cpp. */ - - struct _jvmtiCompiledMethodLoadRecordHeader* next; -} jvmtiCompiledMethodLoadRecordHeader; - -/* - * Record that gives information about the methods on the compile-time - * stack at a specific pc address of a compiled method. Each element in - * the methods array maps to same element in the bcis array. - */ -typedef struct _PCStackInfo { - void* pc; /* the pc address for this compiled method */ - jint numstackframes; /* number of methods on the stack */ - jmethodID* methods; /* array of numstackframes method ids */ - jint* bcis; /* array of numstackframes bytecode indices */ -} PCStackInfo; - -/* - * Record that contains inlining information for each pc address of - * an nmethod. - */ -typedef struct _jvmtiCompiledMethodLoadInlineRecord { - jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */ - jint numpcs; /* number of pc descriptors in this nmethod */ - PCStackInfo* pcinfo; /* array of numpcs pc descriptors */ -} jvmtiCompiledMethodLoadInlineRecord; - -/* - * Dummy record used to test that we can pass records with different - * information through the void pointer provided that they can be cast - * to a jvmtiCompiledMethodLoadRecordHeader. - */ - -typedef struct _jvmtiCompiledMethodLoadDummyRecord { - jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */ - char message[50]; -} jvmtiCompiledMethodLoadDummyRecord; - -#endif diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 1772feedde1..ba0c418aa2b 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -53,9 +53,6 @@ #include "utilities/events.hpp" #include "utilities/resourceHash.hpp" #include "utilities/xmlstream.hpp" -#ifdef SHARK -#include "shark/sharkCompiler.hpp" -#endif #if INCLUDE_JVMCI #include "jvmci/jvmciJavaClasses.hpp" #endif @@ -200,9 +197,6 @@ static java_nmethod_stats_struct c2_java_nmethod_stats; #if INCLUDE_JVMCI static java_nmethod_stats_struct jvmci_java_nmethod_stats; #endif -#ifdef SHARK -static java_nmethod_stats_struct shark_java_nmethod_stats; -#endif static java_nmethod_stats_struct unknown_java_nmethod_stats; static native_nmethod_stats_struct native_nmethod_stats; @@ -223,11 +217,6 @@ static void note_java_nmethod(nmethod* nm) { if (nm->is_compiled_by_jvmci()) { jvmci_java_nmethod_stats.note_nmethod(nm); } else -#endif -#ifdef SHARK - if (nm->is_compiled_by_shark()) { - shark_java_nmethod_stats.note_nmethod(nm); - } else #endif { unknown_java_nmethod_stats.note_nmethod(nm); @@ -411,11 +400,8 @@ void nmethod::init_defaults() { _oops_do_mark_link = NULL; _jmethod_id = NULL; _osr_link = NULL; - if (UseG1GC) { - _unloading_next = NULL; - } else { - _scavenge_root_link = NULL; - } + _unloading_next = NULL; + _scavenge_root_link = NULL; _scavenge_root_state = 0; #if INCLUDE_RTM_OPT _rtm_state = NoRTM; @@ -599,12 +585,9 @@ nmethod::nmethod( code_buffer->copy_code_and_locs_to(this); code_buffer->copy_values_to(this); if (ScavengeRootsInCode) { - if (detect_scavenge_root_oops()) { - CodeCache::add_scavenge_root_nmethod(this); - } Universe::heap()->register_nmethod(this); } - debug_only(verify_scavenge_root_oops()); + debug_only(Universe::heap()->verify_nmethod(this)); CodeCache::commit(this); } @@ -754,12 +737,9 @@ nmethod::nmethod( debug_info->copy_to(this); dependencies->copy_to(this); if (ScavengeRootsInCode) { - if (detect_scavenge_root_oops()) { - CodeCache::add_scavenge_root_nmethod(this); - } Universe::heap()->register_nmethod(this); } - debug_only(verify_scavenge_root_oops()); + debug_only(Universe::heap()->verify_nmethod(this)); CodeCache::commit(this); @@ -1334,10 +1314,6 @@ void nmethod::flush() { CodeCache::drop_scavenge_root_nmethod(this); } -#ifdef SHARK - ((SharkCompiler *) compiler())->free_compiled_method(insts_begin()); -#endif // SHARK - CodeBlob::flush(); CodeCache::free(this); } @@ -1661,20 +1637,16 @@ nmethod* volatile nmethod::_oops_do_mark_nmethods; // This code must be MP safe, because it is used from parallel GC passes. bool nmethod::test_set_oops_do_mark() { assert(nmethod::oops_do_marking_is_active(), "oops_do_marking_prologue must be called"); - nmethod* observed_mark_link = _oops_do_mark_link; - if (observed_mark_link == NULL) { + if (_oops_do_mark_link == NULL) { // Claim this nmethod for this thread to mark. - observed_mark_link = (nmethod*) - Atomic::cmpxchg_ptr(NMETHOD_SENTINEL, &_oops_do_mark_link, NULL); - if (observed_mark_link == NULL) { - + if (Atomic::cmpxchg(NMETHOD_SENTINEL, &_oops_do_mark_link, (nmethod*)NULL) == NULL) { // Atomically append this nmethod (now claimed) to the head of the list: nmethod* observed_mark_nmethods = _oops_do_mark_nmethods; for (;;) { nmethod* required_mark_nmethods = observed_mark_nmethods; _oops_do_mark_link = required_mark_nmethods; - observed_mark_nmethods = (nmethod*) - Atomic::cmpxchg_ptr(this, &_oops_do_mark_nmethods, required_mark_nmethods); + observed_mark_nmethods = + Atomic::cmpxchg(this, &_oops_do_mark_nmethods, required_mark_nmethods); if (observed_mark_nmethods == required_mark_nmethods) break; } @@ -1690,9 +1662,9 @@ bool nmethod::test_set_oops_do_mark() { void nmethod::oops_do_marking_prologue() { if (TraceScavenge) { tty->print_cr("[oops_do_marking_prologue"); } assert(_oops_do_mark_nmethods == NULL, "must not call oops_do_marking_prologue twice in a row"); - // We use cmpxchg_ptr instead of regular assignment here because the user + // We use cmpxchg instead of regular assignment here because the user // may fork a bunch of threads, and we need them all to see the same state. - void* observed = Atomic::cmpxchg_ptr(NMETHOD_SENTINEL, &_oops_do_mark_nmethods, NULL); + nmethod* observed = Atomic::cmpxchg(NMETHOD_SENTINEL, &_oops_do_mark_nmethods, (nmethod*)NULL); guarantee(observed == NULL, "no races in this sequential code"); } @@ -1707,8 +1679,8 @@ void nmethod::oops_do_marking_epilogue() { NOT_PRODUCT(if (TraceScavenge) cur->print_on(tty, "oops_do, unmark")); cur = next; } - void* required = _oops_do_mark_nmethods; - void* observed = Atomic::cmpxchg_ptr(NULL, &_oops_do_mark_nmethods, required); + nmethod* required = _oops_do_mark_nmethods; + nmethod* observed = Atomic::cmpxchg((nmethod*)NULL, &_oops_do_mark_nmethods, required); guarantee(observed == required, "no races in this sequential code"); if (TraceScavenge) { tty->print_cr("oops_do_marking_epilogue]"); } } @@ -2137,7 +2109,7 @@ void nmethod::verify() { VerifyOopsClosure voc(this); oops_do(&voc); assert(voc.ok(), "embedded oops must be OK"); - verify_scavenge_root_oops(); + Universe::heap()->verify_nmethod(this); verify_scopes(); } @@ -2230,10 +2202,6 @@ public: }; void nmethod::verify_scavenge_root_oops() { - if (UseG1GC) { - return; - } - if (!on_scavenge_root_list()) { // Actually look inside, to verify the claim that it's clean. DebugScavengeRoot debug_scavenge_root(this); @@ -2258,8 +2226,6 @@ void nmethod::print() const { tty->print("(c1) "); } else if (is_compiled_by_c2()) { tty->print("(c2) "); - } else if (is_compiled_by_shark()) { - tty->print("(shark) "); } else if (is_compiled_by_jvmci()) { tty->print("(JVMCI) "); } else { @@ -2880,9 +2846,6 @@ void nmethod::print_statistics() { #endif #if INCLUDE_JVMCI jvmci_java_nmethod_stats.print_nmethod_stats("JVMCI"); -#endif -#ifdef SHARK - shark_java_nmethod_stats.print_nmethod_stats("Shark"); #endif unknown_java_nmethod_stats.print_nmethod_stats("Unknown"); DebugInformationRecorder::print_statistics(); diff --git a/src/hotspot/share/code/stubs.cpp b/src/hotspot/share/code/stubs.cpp index 326fcc12130..56883bc623d 100644 --- a/src/hotspot/share/code/stubs.cpp +++ b/src/hotspot/share/code/stubs.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "code/codeBlob.hpp" +#include "code/codeCache.hpp" #include "code/stubs.hpp" #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" @@ -89,6 +90,13 @@ StubQueue::~StubQueue() { Unimplemented(); } +void StubQueue::deallocate_unused_tail() { + CodeBlob* blob = CodeCache::find_blob((void*)_stub_buffer); + CodeCache::free_unused_tail(blob, used_space()); + // Update the limits to the new, trimmed CodeBlob size + _buffer_size = blob->content_size(); + _buffer_limit = blob->content_size(); +} Stub* StubQueue::stub_containing(address pc) const { if (contains(pc)) { diff --git a/src/hotspot/share/code/stubs.hpp b/src/hotspot/share/code/stubs.hpp index b340b4b61f9..ab84ffaada9 100644 --- a/src/hotspot/share/code/stubs.hpp +++ b/src/hotspot/share/code/stubs.hpp @@ -201,12 +201,15 @@ class StubQueue: public CHeapObj { void remove_first(int n); // remove the first n stubs in the queue void remove_all(); // remove all stubs in the queue + void deallocate_unused_tail(); // deallocate the unused tail of the underlying CodeBlob + // only used from TemplateInterpreter::initialize() // Iteration static void queues_do(void f(StubQueue* s)); // call f with each StubQueue void stubs_do(void f(Stub* s)); // call f with all stubs Stub* first() const { return number_of_stubs() > 0 ? stub_at(_queue_begin) : NULL; } Stub* next(Stub* s) const { int i = index_of(s) + stub_size(s); - if (i == _buffer_limit) i = 0; + // Only wrap around in the non-contiguous case (see stubss.cpp) + if (i == _buffer_limit && _queue_end < _buffer_limit) i = 0; return (i == _queue_end) ? NULL : stub_at(i); } diff --git a/src/hotspot/share/compiler/abstractCompiler.hpp b/src/hotspot/share/compiler/abstractCompiler.hpp index 958102bb694..52a93ba3c4a 100644 --- a/src/hotspot/share/compiler/abstractCompiler.hpp +++ b/src/hotspot/share/compiler/abstractCompiler.hpp @@ -152,7 +152,6 @@ class AbstractCompiler : public CHeapObj { const bool is_c1() { return _type == compiler_c1; } const bool is_c2() { return _type == compiler_c2; } const bool is_jvmci() { return _type == compiler_jvmci; } - const bool is_shark() { return _type == compiler_shark; } const CompilerType type() { return _type; } // Extra tests to identify trivial methods for the tiered compilation policy. diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 9dee3fa9fa2..1169842d3d2 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -70,9 +70,6 @@ #ifdef COMPILER2 #include "opto/c2compiler.hpp" #endif -#ifdef SHARK -#include "shark/sharkCompiler.hpp" -#endif #ifdef DTRACE_ENABLED @@ -531,7 +528,6 @@ void CompileBroker::compilation_init(TRAPS) { if (!UseCompiler) { return; } -#ifndef SHARK // Set the interface to the current compiler(s). int c1_count = CompilationPolicy::policy()->compiler_count(CompLevel_simple); int c2_count = CompilationPolicy::policy()->compiler_count(CompLevel_full_optimization); @@ -573,13 +569,6 @@ void CompileBroker::compilation_init(TRAPS) { } #endif // COMPILER2 -#else // SHARK - int c1_count = 0; - int c2_count = 1; - - _compilers[1] = new SharkCompiler(); -#endif // SHARK - // Start the compiler thread(s) and the sweeper thread init_compiler_sweeper_threads(c1_count, c2_count); // totalTime performance counter is always created as it is required @@ -774,9 +763,9 @@ JavaThread* CompileBroker::make_thread(const char* name, CompileQueue* queue, Co void CompileBroker::init_compiler_sweeper_threads(int c1_compiler_count, int c2_compiler_count) { EXCEPTION_MARK; -#if !defined(ZERO) && !defined(SHARK) +#if !defined(ZERO) assert(c2_compiler_count > 0 || c1_compiler_count > 0, "No compilers?"); -#endif // !ZERO && !SHARK +#endif // !ZERO // Initialize the compilation queue if (c2_compiler_count > 0) { const char* name = JVMCI_ONLY(UseJVMCICompiler ? "JVMCI compile queue" :) "C2 compile queue"; @@ -796,7 +785,6 @@ void CompileBroker::init_compiler_sweeper_threads(int c1_compiler_count, int c2_ // Create a name for our thread. sprintf(name_buffer, "%s CompilerThread%d", _compilers[1]->name(), i); CompilerCounters* counters = new CompilerCounters(); - // Shark and C2 make_thread(name_buffer, _c2_compile_queue, counters, _compilers[1], compiler_thread, CHECK); } @@ -1100,7 +1088,7 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci, assert(!HAS_PENDING_EXCEPTION, "No exception should be present"); // some prerequisites that are compiler specific - if (comp->is_c2() || comp->is_shark()) { + if (comp->is_c2()) { method->constants()->resolve_string_constants(CHECK_AND_CLEAR_NULL); // Resolve all classes seen in the signature of the method // we are compiling. @@ -1490,10 +1478,8 @@ bool CompileBroker::init_compiler_runtime() { ThreadInVMfromNative tv(thread); ResetNoHandleMark rnhm; - if (!comp->is_shark()) { - // Perform per-thread and global initializations - comp->initialize(); - } + // Perform per-thread and global initializations + comp->initialize(); } if (comp->is_failed()) { diff --git a/src/hotspot/share/compiler/compileBroker.hpp b/src/hotspot/share/compiler/compileBroker.hpp index 571ee7020e0..ced793a0c4f 100644 --- a/src/hotspot/share/compiler/compileBroker.hpp +++ b/src/hotspot/share/compiler/compileBroker.hpp @@ -332,7 +332,7 @@ public: static void disable_compilation_forever() { UseCompiler = false; AlwaysCompileLoopMethods = false; - Atomic::xchg(shutdown_compilation, &_should_compile_new_jobs); + Atomic::xchg(jint(shutdown_compilation), &_should_compile_new_jobs); } static bool is_compilation_disabled_forever() { diff --git a/src/hotspot/share/compiler/compilerDefinitions.cpp b/src/hotspot/share/compiler/compilerDefinitions.cpp index bcec3ffa20d..0139ceb25f3 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.cpp +++ b/src/hotspot/share/compiler/compilerDefinitions.cpp @@ -31,11 +31,10 @@ const char* compilertype2name_tab[compiler_number_of_types] = { "", "c1", "c2", - "jvmci", - "shark" + "jvmci" }; -#if defined(COMPILER2) || defined(SHARK) +#if defined(COMPILER2) CompLevel CompLevel_highest_tier = CompLevel_full_optimization; // pure C2 and tiered or JVMCI and tiered #elif defined(COMPILER1) CompLevel CompLevel_highest_tier = CompLevel_simple; // pure C1 or JVMCI @@ -47,7 +46,7 @@ CompLevel CompLevel_highest_tier = CompLevel_none; CompLevel CompLevel_initial_compile = CompLevel_full_profile; // tiered #elif defined(COMPILER1) || INCLUDE_JVMCI CompLevel CompLevel_initial_compile = CompLevel_simple; // pure C1 or JVMCI -#elif defined(COMPILER2) || defined(SHARK) +#elif defined(COMPILER2) CompLevel CompLevel_initial_compile = CompLevel_full_optimization; // pure C2 #else CompLevel CompLevel_initial_compile = CompLevel_none; diff --git a/src/hotspot/share/compiler/compilerDefinitions.hpp b/src/hotspot/share/compiler/compilerDefinitions.hpp index a2378ea1e92..16ae7b0e3af 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.hpp +++ b/src/hotspot/share/compiler/compilerDefinitions.hpp @@ -33,7 +33,6 @@ enum CompilerType { compiler_c1, compiler_c2, compiler_jvmci, - compiler_shark, compiler_number_of_types }; @@ -54,7 +53,7 @@ enum CompLevel { CompLevel_simple = 1, // C1 CompLevel_limited_profile = 2, // C1, invocation & backedge counters CompLevel_full_profile = 3, // C1, invocation & backedge counters + mdo - CompLevel_full_optimization = 4 // C2, Shark or JVMCI + CompLevel_full_optimization = 4 // C2 or JVMCI }; extern CompLevel CompLevel_highest_tier; diff --git a/src/hotspot/share/compiler/compilerDirectives.cpp b/src/hotspot/share/compiler/compilerDirectives.cpp index 467a89d6e14..e3181e00c12 100644 --- a/src/hotspot/share/compiler/compilerDirectives.cpp +++ b/src/hotspot/share/compiler/compilerDirectives.cpp @@ -171,7 +171,7 @@ DirectiveSet* CompilerDirectives::get_for(AbstractCompiler *comp) { return _c2_store; } else { // use c1_store as default - assert(comp->is_c1() || comp->is_jvmci() || comp->is_shark(), ""); + assert(comp->is_c1() || comp->is_jvmci(), ""); return _c1_store; } } diff --git a/src/hotspot/share/compiler/disassembler.cpp b/src/hotspot/share/compiler/disassembler.cpp index d5e6f66f440..bb36edbc58d 100644 --- a/src/hotspot/share/compiler/disassembler.cpp +++ b/src/hotspot/share/compiler/disassembler.cpp @@ -35,9 +35,6 @@ #include "runtime/stubCodeGenerator.hpp" #include "runtime/stubRoutines.hpp" #include CPU_HEADER(depChecker) -#ifdef SHARK -#include "shark/sharkEntry.hpp" -#endif void* Disassembler::_library = NULL; bool Disassembler::_tried_to_load_library = false; @@ -521,14 +518,8 @@ void Disassembler::decode(nmethod* nm, outputStream* st) { decode_env env(nm, st); env.output()->print_cr("----------------------------------------------------------------------"); -#ifdef SHARK - SharkEntry* entry = (SharkEntry *) nm->code_begin(); - unsigned char* p = entry->code_start(); - unsigned char* end = entry->code_limit(); -#else unsigned char* p = nm->code_begin(); unsigned char* end = nm->code_end(); -#endif // SHARK nm->method()->method_holder()->name()->print_symbol_on(env.output()); env.output()->print("."); diff --git a/src/hotspot/share/compiler/methodMatcher.cpp b/src/hotspot/share/compiler/methodMatcher.cpp index 8113d859cff..cc84fb53e8b 100644 --- a/src/hotspot/share/compiler/methodMatcher.cpp +++ b/src/hotspot/share/compiler/methodMatcher.cpp @@ -96,7 +96,7 @@ bool MethodMatcher::canonicalize(char * line, const char *& error_msg) { bool have_colon = (colon != NULL); if (have_colon) { // Don't allow multiple '::' - if (colon + 2 != '\0') { + if (colon[2] != '\0') { if (strstr(colon+2, "::")) { error_msg = "Method pattern only allows one '::' allowed"; return false; diff --git a/src/hotspot/share/compiler/oopMap.cpp b/src/hotspot/share/compiler/oopMap.cpp index 7759615c4ce..e412e4bf2d0 100644 --- a/src/hotspot/share/compiler/oopMap.cpp +++ b/src/hotspot/share/compiler/oopMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, 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 @@ -30,6 +30,7 @@ #include "compiler/oopMap.hpp" #include "gc/shared/collectedHeap.hpp" #include "memory/allocation.inline.hpp" +#include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "runtime/frame.inline.hpp" #include "runtime/signature.hpp" @@ -40,9 +41,6 @@ #ifdef COMPILER2 #include "opto/optoreg.hpp" #endif -#ifdef SPARC -#include "vmreg_sparc.inline.hpp" -#endif // OopMapStream @@ -266,13 +264,6 @@ OopMap* OopMapSet::find_map_at_offset(int pc_offset) const { return m; } -class DoNothingClosure: public OopClosure { - public: - void do_oop(oop* p) {} - void do_oop(narrowOop* p) {} -}; -static DoNothingClosure do_nothing; - static void add_derived_oop(oop* base, oop* derived) { #if !defined(TIERED) && !defined(INCLUDE_JVMCI) COMPILER1_PRESENT(ShouldNotReachHere();) @@ -313,7 +304,7 @@ static void trace_codeblob_maps(const frame *fr, const RegisterMap *reg_map) { void OopMapSet::oops_do(const frame *fr, const RegisterMap* reg_map, OopClosure* f) { // add derived oops to a table - all_do(fr, reg_map, f, add_derived_oop, &do_nothing); + all_do(fr, reg_map, f, add_derived_oop, &do_nothing_cl); } diff --git a/src/hotspot/share/gc/cms/cmsHeap.cpp b/src/hotspot/share/gc/cms/cmsHeap.cpp new file mode 100644 index 00000000000..da344cce24d --- /dev/null +++ b/src/hotspot/share/gc/cms/cmsHeap.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2017, 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 "precompiled.hpp" +#include "gc/cms/concurrentMarkSweepThread.hpp" +#include "gc/cms/cmsHeap.hpp" +#include "gc/cms/vmCMSOperations.hpp" +#include "gc/shared/genOopClosures.inline.hpp" +#include "gc/shared/strongRootsScope.hpp" +#include "gc/shared/workgroup.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/vmThread.hpp" +#include "utilities/stack.inline.hpp" + +CMSHeap::CMSHeap(GenCollectorPolicy *policy) : GenCollectedHeap(policy) { + _workers = new WorkGang("GC Thread", ParallelGCThreads, + /* are_GC_task_threads */true, + /* are_ConcurrentGC_threads */false); + _workers->initialize_workers(); +} + +jint CMSHeap::initialize() { + jint status = GenCollectedHeap::initialize(); + if (status != JNI_OK) return status; + + // If we are running CMS, create the collector responsible + // for collecting the CMS generations. + assert(collector_policy()->is_concurrent_mark_sweep_policy(), "must be CMS policy"); + if (!create_cms_collector()) { + return JNI_ENOMEM; + } + + return JNI_OK; +} + +void CMSHeap::check_gen_kinds() { + assert(young_gen()->kind() == Generation::ParNew, + "Wrong youngest generation type"); + assert(old_gen()->kind() == Generation::ConcurrentMarkSweep, + "Wrong generation kind"); +} + +CMSHeap* CMSHeap::heap() { + CollectedHeap* heap = Universe::heap(); + assert(heap != NULL, "Uninitialized access to CMSHeap::heap()"); + assert(heap->kind() == CollectedHeap::CMSHeap, "Not a CMSHeap"); + return (CMSHeap*) heap; +} + +void CMSHeap::gc_threads_do(ThreadClosure* tc) const { + assert(workers() != NULL, "should have workers here"); + workers()->threads_do(tc); + ConcurrentMarkSweepThread::threads_do(tc); +} + +void CMSHeap::print_gc_threads_on(outputStream* st) const { + assert(workers() != NULL, "should have workers here"); + workers()->print_worker_threads_on(st); + ConcurrentMarkSweepThread::print_all_on(st); +} + +void CMSHeap::print_on_error(outputStream* st) const { + GenCollectedHeap::print_on_error(st); + st->cr(); + CMSCollector::print_on_error(st); +} + +bool CMSHeap::create_cms_collector() { + assert(old_gen()->kind() == Generation::ConcurrentMarkSweep, + "Unexpected generation kinds"); + assert(gen_policy()->is_concurrent_mark_sweep_policy(), "Unexpected policy type"); + CMSCollector* collector = + new CMSCollector((ConcurrentMarkSweepGeneration*) old_gen(), + rem_set(), + gen_policy()->as_concurrent_mark_sweep_policy()); + + if (collector == NULL || !collector->completed_initialization()) { + if (collector) { + delete collector; // Be nice in embedded situation + } + vm_shutdown_during_initialization("Could not create CMS collector"); + return false; + } + return true; // success +} + +void CMSHeap::collect(GCCause::Cause cause) { + if (should_do_concurrent_full_gc(cause)) { + // Mostly concurrent full collection. + collect_mostly_concurrent(cause); + } else { + GenCollectedHeap::collect(cause); + } +} + +bool CMSHeap::should_do_concurrent_full_gc(GCCause::Cause cause) { + switch (cause) { + case GCCause::_gc_locker: return GCLockerInvokesConcurrent; + case GCCause::_java_lang_system_gc: + case GCCause::_dcmd_gc_run: return ExplicitGCInvokesConcurrent; + default: return false; + } +} + +void CMSHeap::collect_mostly_concurrent(GCCause::Cause cause) { + assert(!Heap_lock->owned_by_self(), "Should not own Heap_lock"); + + MutexLocker ml(Heap_lock); + // Read the GC counts while holding the Heap_lock + unsigned int full_gc_count_before = total_full_collections(); + unsigned int gc_count_before = total_collections(); + { + MutexUnlocker mu(Heap_lock); + VM_GenCollectFullConcurrent op(gc_count_before, full_gc_count_before, cause); + VMThread::execute(&op); + } +} + +void CMSHeap::stop() { + ConcurrentMarkSweepThread::cmst()->stop(); +} + +void CMSHeap::safepoint_synchronize_begin() { + ConcurrentMarkSweepThread::synchronize(false); +} + +void CMSHeap::safepoint_synchronize_end() { + ConcurrentMarkSweepThread::desynchronize(false); +} + +void CMSHeap::cms_process_roots(StrongRootsScope* scope, + bool young_gen_as_roots, + ScanningOption so, + bool only_strong_roots, + OopsInGenClosure* root_closure, + CLDClosure* cld_closure) { + MarkingCodeBlobClosure mark_code_closure(root_closure, !CodeBlobToOopClosure::FixRelocations); + OopsInGenClosure* weak_roots = only_strong_roots ? NULL : root_closure; + CLDClosure* weak_cld_closure = only_strong_roots ? NULL : cld_closure; + + process_roots(scope, so, root_closure, weak_roots, cld_closure, weak_cld_closure, &mark_code_closure); + if (!only_strong_roots) { + process_string_table_roots(scope, root_closure); + } + + if (young_gen_as_roots && + !_process_strong_tasks->is_task_claimed(GCH_PS_younger_gens)) { + root_closure->set_generation(young_gen()); + young_gen()->oop_iterate(root_closure); + root_closure->reset_generation(); + } + + _process_strong_tasks->all_tasks_completed(scope->n_threads()); +} + +void CMSHeap::gc_prologue(bool full) { + always_do_update_barrier = false; + GenCollectedHeap::gc_prologue(full); +}; + +void CMSHeap::gc_epilogue(bool full) { + GenCollectedHeap::gc_epilogue(full); + always_do_update_barrier = true; +}; diff --git a/src/hotspot/share/gc/cms/cmsHeap.hpp b/src/hotspot/share/gc/cms/cmsHeap.hpp new file mode 100644 index 00000000000..82fbd4107a5 --- /dev/null +++ b/src/hotspot/share/gc/cms/cmsHeap.hpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2017, 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. + * + */ + +#ifndef SHARE_VM_GC_CMS_CMSHEAP_HPP +#define SHARE_VM_GC_CMS_CMSHEAP_HPP + +#include "gc/cms/concurrentMarkSweepGeneration.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/gcCause.hpp" +#include "gc/shared/genCollectedHeap.hpp" + +class CLDClosure; +class GenCollectorPolicy; +class OopsInGenClosure; +class outputStream; +class StrongRootsScope; +class ThreadClosure; +class WorkGang; + +class CMSHeap : public GenCollectedHeap { +public: + CMSHeap(GenCollectorPolicy *policy); + + // Returns JNI_OK on success + virtual jint initialize(); + + virtual void check_gen_kinds(); + + // Convenience function to be used in situations where the heap type can be + // asserted to be this type. + static CMSHeap* heap(); + + virtual Name kind() const { + return CollectedHeap::CMSHeap; + } + + virtual const char* name() const { + return "Concurrent Mark Sweep"; + } + + WorkGang* workers() const { return _workers; } + + virtual void print_gc_threads_on(outputStream* st) const; + virtual void gc_threads_do(ThreadClosure* tc) const; + virtual void print_on_error(outputStream* st) const; + + // Perform a full collection of the heap; intended for use in implementing + // "System.gc". This implies as full a collection as the CollectedHeap + // supports. Caller does not hold the Heap_lock on entry. + void collect(GCCause::Cause cause); + + bool is_in_closed_subset(const void* p) const { + return is_in_reserved(p); + } + + bool card_mark_must_follow_store() const { + return true; + } + + void stop(); + void safepoint_synchronize_begin(); + void safepoint_synchronize_end(); + + // If "young_gen_as_roots" is false, younger generations are + // not scanned as roots; in this case, the caller must be arranging to + // scan the younger generations itself. (For example, a generation might + // explicitly mark reachable objects in younger generations, to avoid + // excess storage retention.) + void cms_process_roots(StrongRootsScope* scope, + bool young_gen_as_roots, + ScanningOption so, + bool only_strong_roots, + OopsInGenClosure* root_closure, + CLDClosure* cld_closure); + +private: + WorkGang* _workers; + + virtual void gc_prologue(bool full); + virtual void gc_epilogue(bool full); + + // Accessor for memory state verification support + NOT_PRODUCT( + virtual size_t skip_header_HeapWords() { return CMSCollector::skip_header_HeapWords(); } + ) + + // Returns success or failure. + bool create_cms_collector(); + + // In support of ExplicitGCInvokesConcurrent functionality + bool should_do_concurrent_full_gc(GCCause::Cause cause); + + void collect_mostly_concurrent(GCCause::Cause cause); +}; + +#endif // SHARE_VM_GC_CMS_CMSHEAP_HPP diff --git a/src/hotspot/share/gc/cms/cmsOopClosures.hpp b/src/hotspot/share/gc/cms/cmsOopClosures.hpp index 11416afebc9..ab29b0136cd 100644 --- a/src/hotspot/share/gc/cms/cmsOopClosures.hpp +++ b/src/hotspot/share/gc/cms/cmsOopClosures.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2017, 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 @@ -48,12 +48,7 @@ class ParMarkFromRootsClosure; // because some CMS OopClosures derive from OopsInGenClosure. It would be // good to get rid of them completely. class MetadataAwareOopsInGenClosure: public OopsInGenClosure { - KlassToOopClosure _klass_closure; public: - MetadataAwareOopsInGenClosure() { - _klass_closure.initialize(this); - } - virtual bool do_metadata() { return do_metadata_nv(); } inline bool do_metadata_nv() { return true; } diff --git a/src/hotspot/share/gc/cms/cmsOopClosures.inline.hpp b/src/hotspot/share/gc/cms/cmsOopClosures.inline.hpp index 36a6e841cfc..ad01a9d45d7 100644 --- a/src/hotspot/share/gc/cms/cmsOopClosures.inline.hpp +++ b/src/hotspot/share/gc/cms/cmsOopClosures.inline.hpp @@ -40,10 +40,8 @@ inline void MetadataAwareOopsInGenClosure::do_klass_nv(Klass* k) { inline void MetadataAwareOopsInGenClosure::do_klass(Klass* k) { do_klass_nv(k); } inline void MetadataAwareOopsInGenClosure::do_cld_nv(ClassLoaderData* cld) { - assert(_klass_closure._oop_closure == this, "Must be"); - bool claim = true; // Must claim the class loader data before processing. - cld->oops_do(_klass_closure._oop_closure, &_klass_closure, claim); + cld->oops_do(this, claim); } // Decode the oop and call do_oop on it. diff --git a/src/hotspot/share/gc/cms/compactibleFreeListSpace.cpp b/src/hotspot/share/gc/cms/compactibleFreeListSpace.cpp index 3653c4df24f..34116c60433 100644 --- a/src/hotspot/share/gc/cms/compactibleFreeListSpace.cpp +++ b/src/hotspot/share/gc/cms/compactibleFreeListSpace.cpp @@ -23,13 +23,13 @@ */ #include "precompiled.hpp" +#include "gc/cms/cmsHeap.hpp" #include "gc/cms/cmsLockVerifier.hpp" #include "gc/cms/compactibleFreeListSpace.hpp" #include "gc/cms/concurrentMarkSweepGeneration.inline.hpp" #include "gc/cms/concurrentMarkSweepThread.hpp" #include "gc/shared/blockOffsetTable.inline.hpp" #include "gc/shared/collectedHeap.inline.hpp" -#include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/space.inline.hpp" #include "gc/shared/spaceDecorator.hpp" #include "logging/log.hpp" @@ -154,7 +154,7 @@ HeapWord* CompactibleFreeListSpace::forward(oop q, size_t size, cp->space->set_compaction_top(compact_top); cp->space = cp->space->next_compaction_space(); if (cp->space == NULL) { - cp->gen = GenCollectedHeap::heap()->young_gen(); + cp->gen = CMSHeap::heap()->young_gen(); assert(cp->gen != NULL, "compaction must succeed"); cp->space = cp->gen->first_compaction_space(); assert(cp->space != NULL, "generation must have a first compaction space"); @@ -2298,7 +2298,7 @@ void CompactibleFreeListSpace::verify() const { // Iterate over all oops in the heap. Uses the _no_header version // since we are not interested in following the klass pointers. - GenCollectedHeap::heap()->oop_iterate_no_header(&cl); + CMSHeap::heap()->oop_iterate_no_header(&cl); } if (VerifyObjectStartArray) { diff --git a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp index 22d5030ba72..0901117f646 100644 --- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp +++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp @@ -29,6 +29,7 @@ #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "gc/cms/cmsCollectorPolicy.hpp" +#include "gc/cms/cmsHeap.hpp" #include "gc/cms/cmsOopClosures.inline.hpp" #include "gc/cms/compactibleFreeListSpace.hpp" #include "gc/cms/concurrentMarkSweepGeneration.inline.hpp" @@ -54,6 +55,7 @@ #include "gc/shared/referencePolicy.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskqueue.inline.hpp" +#include "gc/shared/weakProcessor.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/allocation.hpp" @@ -298,14 +300,14 @@ void CMSCollector::ref_processor_init() { } AdaptiveSizePolicy* CMSCollector::size_policy() { - GenCollectedHeap* gch = GenCollectedHeap::heap(); - return gch->gen_policy()->size_policy(); + CMSHeap* heap = CMSHeap::heap(); + return heap->gen_policy()->size_policy(); } void ConcurrentMarkSweepGeneration::initialize_performance_counters() { const char* gen_name = "old"; - GenCollectorPolicy* gcp = GenCollectedHeap::heap()->gen_policy(); + GenCollectorPolicy* gcp = CMSHeap::heap()->gen_policy(); // Generation Counters - generation 1, 1 subspace _gen_counters = new GenerationCounters(gen_name, 1, 1, gcp->min_old_size(), gcp->max_old_size(), &_virtual_space); @@ -354,8 +356,8 @@ void CMSStats::adjust_cms_free_adjustment_factor(bool fail, size_t free) { // young generation collection. double CMSStats::time_until_cms_gen_full() const { size_t cms_free = _cms_gen->cmsSpace()->free(); - GenCollectedHeap* gch = GenCollectedHeap::heap(); - size_t expected_promotion = MIN2(gch->young_gen()->capacity(), + CMSHeap* heap = CMSHeap::heap(); + size_t expected_promotion = MIN2(heap->young_gen()->capacity(), (size_t) _cms_gen->gc_stats()->avg_promoted()->padded_average()); if (cms_free > expected_promotion) { // Start a cms collection if there isn't enough space to promote @@ -595,12 +597,12 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, assert(CGC_lock != NULL, "Where's the CGC_lock?"); // Support for parallelizing young gen rescan - GenCollectedHeap* gch = GenCollectedHeap::heap(); - assert(gch->young_gen()->kind() == Generation::ParNew, "CMS can only be used with ParNew"); - _young_gen = (ParNewGeneration*)gch->young_gen(); - if (gch->supports_inline_contig_alloc()) { - _top_addr = gch->top_addr(); - _end_addr = gch->end_addr(); + CMSHeap* heap = CMSHeap::heap(); + assert(heap->young_gen()->kind() == Generation::ParNew, "CMS can only be used with ParNew"); + _young_gen = (ParNewGeneration*)heap->young_gen(); + if (heap->supports_inline_contig_alloc()) { + _top_addr = heap->top_addr(); + _end_addr = heap->end_addr(); assert(_young_gen != NULL, "no _young_gen"); _eden_chunk_index = 0; _eden_chunk_capacity = (_young_gen->max_capacity() + CMSSamplingGrain) / CMSSamplingGrain; @@ -762,9 +764,9 @@ void ConcurrentMarkSweepGeneration::compute_new_size_free_list() { log.trace(" Maximum free fraction %f", maximum_free_percentage); log.trace(" Capacity " SIZE_FORMAT, capacity() / 1000); log.trace(" Desired capacity " SIZE_FORMAT, desired_capacity / 1000); - GenCollectedHeap* gch = GenCollectedHeap::heap(); - assert(gch->is_old_gen(this), "The CMS generation should always be the old generation"); - size_t young_size = gch->young_gen()->capacity(); + CMSHeap* heap = CMSHeap::heap(); + assert(heap->is_old_gen(this), "The CMS generation should always be the old generation"); + size_t young_size = heap->young_gen()->capacity(); log.trace(" Young gen size " SIZE_FORMAT, young_size / 1000); log.trace(" unsafe_max_alloc_nogc " SIZE_FORMAT, unsafe_max_alloc_nogc() / 1000); log.trace(" contiguous available " SIZE_FORMAT, contiguous_available() / 1000); @@ -923,7 +925,7 @@ oop ConcurrentMarkSweepGeneration::promote(oop obj, size_t obj_size) { assert_lock_strong(freelistLock()); #ifndef PRODUCT - if (GenCollectedHeap::heap()->promotion_should_fail()) { + if (CMSHeap::heap()->promotion_should_fail()) { return NULL; } #endif // #ifndef PRODUCT @@ -1000,7 +1002,7 @@ ConcurrentMarkSweepGeneration::par_promote(int thread_num, oop old, markOop m, size_t word_sz) { #ifndef PRODUCT - if (GenCollectedHeap::heap()->promotion_should_fail()) { + if (CMSHeap::heap()->promotion_should_fail()) { return NULL; } #endif // #ifndef PRODUCT @@ -1075,8 +1077,8 @@ ConcurrentMarkSweepGeneration::par_promote(int thread_num, obj_ptr, old->is_objArray(), word_sz); NOT_PRODUCT( - Atomic::inc_ptr(&_numObjectsPromoted); - Atomic::add_ptr(alloc_sz, &_numWordsPromoted); + Atomic::inc(&_numObjectsPromoted); + Atomic::add(alloc_sz, &_numWordsPromoted); ) return obj; @@ -1179,10 +1181,10 @@ bool CMSCollector::shouldConcurrentCollect() { // We start a collection if we believe an incremental collection may fail; // this is not likely to be productive in practice because it's probably too // late anyway. - GenCollectedHeap* gch = GenCollectedHeap::heap(); - assert(gch->collector_policy()->is_generation_policy(), + CMSHeap* heap = CMSHeap::heap(); + assert(heap->collector_policy()->is_generation_policy(), "You may want to check the correctness of the following"); - if (gch->incremental_collection_will_fail(true /* consult_young */)) { + if (heap->incremental_collection_will_fail(true /* consult_young */)) { log.print("CMSCollector: collect because incremental collection will fail "); return true; } @@ -1294,8 +1296,8 @@ void CMSCollector::collect(bool full, } void CMSCollector::request_full_gc(unsigned int full_gc_count, GCCause::Cause cause) { - GenCollectedHeap* gch = GenCollectedHeap::heap(); - unsigned int gc_count = gch->total_full_collections(); + CMSHeap* heap = CMSHeap::heap(); + unsigned int gc_count = heap->total_full_collections(); if (gc_count == full_gc_count) { MutexLockerEx y(CGC_lock, Mutex::_no_safepoint_check_flag); _full_gc_requested = true; @@ -1307,7 +1309,7 @@ void CMSCollector::request_full_gc(unsigned int full_gc_count, GCCause::Cause ca } bool CMSCollector::is_external_interruption() { - GCCause::Cause cause = GenCollectedHeap::heap()->gc_cause(); + GCCause::Cause cause = CMSHeap::heap()->gc_cause(); return GCCause::is_user_requested_gc(cause) || GCCause::is_serviceability_requested_gc(cause); } @@ -1456,8 +1458,8 @@ void CMSCollector::acquire_control_and_collect(bool full, // Inform cms gen if this was due to partial collection failing. // The CMS gen may use this fact to determine its expansion policy. - GenCollectedHeap* gch = GenCollectedHeap::heap(); - if (gch->incremental_collection_will_fail(false /* don't consult_young */)) { + CMSHeap* heap = CMSHeap::heap(); + if (heap->incremental_collection_will_fail(false /* don't consult_young */)) { assert(!_cmsGen->incremental_collection_failed(), "Should have been noticed, reacted to and cleared"); _cmsGen->set_incremental_collection_failed(); @@ -1489,14 +1491,14 @@ void CMSCollector::acquire_control_and_collect(bool full, // Has the GC time limit been exceeded? size_t max_eden_size = _young_gen->max_eden_size(); - GCCause::Cause gc_cause = gch->gc_cause(); + GCCause::Cause gc_cause = heap->gc_cause(); size_policy()->check_gc_overhead_limit(_young_gen->used(), _young_gen->eden()->used(), _cmsGen->max_capacity(), max_eden_size, full, gc_cause, - gch->collector_policy()); + heap->collector_policy()); // Reset the expansion cause, now that we just completed // a collection cycle. @@ -1518,21 +1520,21 @@ void CMSCollector::compute_new_size() { // A work method used by the foreground collector to do // a mark-sweep-compact. void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); STWGCTimer* gc_timer = GenMarkSweep::gc_timer(); gc_timer->register_gc_start(); SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer(); - gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start()); + gc_tracer->report_gc_start(heap->gc_cause(), gc_timer->gc_start()); - gch->pre_full_gc_dump(gc_timer); + heap->pre_full_gc_dump(gc_timer); GCTraceTime(Trace, gc, phases) t("CMS:MSC"); // Temporarily widen the span of the weak reference processing to // the entire heap. - MemRegion new_span(GenCollectedHeap::heap()->reserved_region()); + MemRegion new_span(CMSHeap::heap()->reserved_region()); ReferenceProcessorSpanMutator rp_mut_span(ref_processor(), new_span); // Temporarily, clear the "is_alive_non_header" field of the // reference processor. @@ -1553,9 +1555,10 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { assert(_collectorState != Idling || _modUnionTable.isAllClear(), "_modUnionTable should be clear if the baton was not passed"); _modUnionTable.clear_all(); - assert(_collectorState != Idling || _ct->klass_rem_set()->mod_union_is_clear(), + assert(_collectorState != Idling || _ct->cld_rem_set()->mod_union_is_clear(), "mod union for klasses should be clear if the baton was passed"); - _ct->klass_rem_set()->clear_mod_union(); + _ct->cld_rem_set()->clear_mod_union(); + // We must adjust the allocation statistics being maintained // in the free list space. We do so by reading and clearing @@ -1607,7 +1610,7 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { // No longer a need to do a concurrent collection for Metaspace. MetaspaceGC::set_should_concurrent_collect(false); - gch->post_full_gc_dump(gc_timer); + heap->post_full_gc_dump(gc_timer); gc_timer->register_gc_end(); @@ -1701,7 +1704,7 @@ void CMSCollector::collect_in_background(GCCause::Cause cause) { assert(Thread::current()->is_ConcurrentGC_thread(), "A CMS asynchronous collection is only allowed on a CMS thread."); - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); { bool safepoint_check = Mutex::_no_safepoint_check_flag; MutexLockerEx hl(Heap_lock, safepoint_check); @@ -1730,8 +1733,8 @@ void CMSCollector::collect_in_background(GCCause::Cause cause) { _full_gc_requested = false; // acks all outstanding full gc requests _full_gc_cause = GCCause::_no_gc; // Signal that we are about to start a collection - gch->increment_total_full_collections(); // ... starting a collection cycle - _collection_count_start = gch->total_full_collections(); + heap->increment_total_full_collections(); // ... starting a collection cycle + _collection_count_start = heap->total_full_collections(); } size_t prev_used = _cmsGen->used(); @@ -1924,9 +1927,9 @@ void CMSCollector::register_gc_end() { } void CMSCollector::save_heap_summary() { - GenCollectedHeap* gch = GenCollectedHeap::heap(); - _last_heap_summary = gch->create_heap_summary(); - _last_metaspace_summary = gch->create_metaspace_summary(); + CMSHeap* heap = CMSHeap::heap(); + _last_heap_summary = heap->create_heap_summary(); + _last_metaspace_summary = heap->create_metaspace_summary(); } void CMSCollector::report_heap_summary(GCWhen::Type when) { @@ -2025,7 +2028,7 @@ void CMSCollector::gc_prologue(bool full) { // that information. Tell the young collection to save the union of all // modified klasses. if (duringMarking) { - _ct->klass_rem_set()->set_accumulate_modified_oops(true); + _ct->cld_rem_set()->set_accumulate_modified_oops(true); } bool registerClosure = duringMarking; @@ -2101,7 +2104,7 @@ void CMSCollector::gc_epilogue(bool full) { assert(haveFreelistLocks(), "must have freelist locks"); assert_lock_strong(bitMapLock()); - _ct->klass_rem_set()->set_accumulate_modified_oops(false); + _ct->cld_rem_set()->set_accumulate_modified_oops(false); _cmsGen->gc_epilogue_work(full); @@ -2302,10 +2305,10 @@ bool CMSCollector::verify_after_remark() { assert(verification_mark_stack()->isEmpty(), "markStack should be empty"); verify_work_stacks_empty(); - GenCollectedHeap* gch = GenCollectedHeap::heap(); - gch->ensure_parsability(false); // fill TLABs, but no need to retire them + CMSHeap* heap = CMSHeap::heap(); + heap->ensure_parsability(false); // fill TLABs, but no need to retire them // Update the saved marks which may affect the root scans. - gch->save_marks(); + heap->save_marks(); if (CMSRemarkVerifyVariant == 1) { // In this first variant of verification, we complete @@ -2328,19 +2331,19 @@ bool CMSCollector::verify_after_remark() { void CMSCollector::verify_after_remark_work_1() { ResourceMark rm; HandleMark hm; - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); // Get a clear set of claim bits for the roots processing to work with. ClassLoaderDataGraph::clear_claimed_marks(); // Mark from roots one level into CMS MarkRefsIntoClosure notOlder(_span, verification_mark_bm()); - gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. + heap->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. { StrongRootsScope srs(1); - gch->cms_process_roots(&srs, + heap->cms_process_roots(&srs, true, // young gen as roots GenCollectedHeap::ScanningOption(roots_scanning_options()), should_unload_classes(), @@ -2375,30 +2378,30 @@ void CMSCollector::verify_after_remark_work_1() { log.error("Failed marking verification after remark"); ResourceMark rm; LogStream ls(log.error()); - gch->print_on(&ls); + heap->print_on(&ls); fatal("CMS: failed marking verification after remark"); } } -class VerifyKlassOopsKlassClosure : public KlassClosure { - class VerifyKlassOopsClosure : public OopClosure { +class VerifyCLDOopsCLDClosure : public CLDClosure { + class VerifyCLDOopsClosure : public OopClosure { CMSBitMap* _bitmap; public: - VerifyKlassOopsClosure(CMSBitMap* bitmap) : _bitmap(bitmap) { } + VerifyCLDOopsClosure(CMSBitMap* bitmap) : _bitmap(bitmap) { } void do_oop(oop* p) { guarantee(*p == NULL || _bitmap->isMarked((HeapWord*) *p), "Should be marked"); } void do_oop(narrowOop* p) { ShouldNotReachHere(); } } _oop_closure; public: - VerifyKlassOopsKlassClosure(CMSBitMap* bitmap) : _oop_closure(bitmap) {} - void do_klass(Klass* k) { - k->oops_do(&_oop_closure); + VerifyCLDOopsCLDClosure(CMSBitMap* bitmap) : _oop_closure(bitmap) {} + void do_cld(ClassLoaderData* cld) { + cld->oops_do(&_oop_closure, false, false); } }; void CMSCollector::verify_after_remark_work_2() { ResourceMark rm; HandleMark hm; - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); // Get a clear set of claim bits for the roots processing to work with. ClassLoaderDataGraph::clear_claimed_marks(); @@ -2408,12 +2411,12 @@ void CMSCollector::verify_after_remark_work_2() { markBitMap()); CLDToOopClosure cld_closure(¬Older, true); - gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. + heap->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. { StrongRootsScope srs(1); - gch->cms_process_roots(&srs, + heap->cms_process_roots(&srs, true, // young gen as roots GenCollectedHeap::ScanningOption(roots_scanning_options()), should_unload_classes(), @@ -2437,8 +2440,8 @@ void CMSCollector::verify_after_remark_work_2() { assert(verification_mark_stack()->isEmpty(), "Should have been drained"); verify_work_stacks_empty(); - VerifyKlassOopsKlassClosure verify_klass_oops(verification_mark_bm()); - ClassLoaderDataGraph::classes_do(&verify_klass_oops); + VerifyCLDOopsCLDClosure verify_cld_oops(verification_mark_bm()); + ClassLoaderDataGraph::cld_do(&verify_cld_oops); // Marking completed -- now verify that each bit marked in // verification_mark_bm() is also marked in markBitMap(); flag all @@ -2802,7 +2805,7 @@ class CMSParInitialMarkTask: public CMSParMarkTask { void CMSCollector::checkpointRootsInitial() { assert(_collectorState == InitialMarking, "Wrong collector state"); check_correct_thread_executing(); - TraceCMSMemoryManagerStats tms(_collectorState,GenCollectedHeap::heap()->gc_cause()); + TraceCMSMemoryManagerStats tms(_collectorState, CMSHeap::heap()->gc_cause()); save_heap_summary(); report_heap_summary(GCWhen::BeforeGC); @@ -2843,14 +2846,14 @@ void CMSCollector::checkpointRootsInitialWork() { HandleMark hm; MarkRefsIntoClosure notOlder(_span, &_markBitMap); - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); verify_work_stacks_empty(); verify_overflow_empty(); - gch->ensure_parsability(false); // fill TLABs, but no need to retire them + heap->ensure_parsability(false); // fill TLABs, but no need to retire them // Update the saved marks which may affect the root scans. - gch->save_marks(); + heap->save_marks(); // weak reference processing has not started yet. ref_processor()->set_enqueuing_is_done(false); @@ -2871,7 +2874,7 @@ void CMSCollector::checkpointRootsInitialWork() { #endif if (CMSParallelInitialMarkEnabled) { // The parallel version. - WorkGang* workers = gch->workers(); + WorkGang* workers = heap->workers(); assert(workers != NULL, "Need parallel worker threads."); uint n_workers = workers->active_workers(); @@ -2890,11 +2893,11 @@ void CMSCollector::checkpointRootsInitialWork() { } else { // The serial version. CLDToOopClosure cld_closure(¬Older, true); - gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. + heap->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. StrongRootsScope srs(1); - gch->cms_process_roots(&srs, + heap->cms_process_roots(&srs, true, // young gen as roots GenCollectedHeap::ScanningOption(roots_scanning_options()), should_unload_classes(), @@ -2911,7 +2914,7 @@ void CMSCollector::checkpointRootsInitialWork() { " or no bits are set in the gc_prologue before the start of the next " "subsequent marking phase."); - assert(_ct->klass_rem_set()->mod_union_is_clear(), "Must be"); + assert(_ct->cld_rem_set()->mod_union_is_clear(), "Must be"); // Save the end of the used_region of the constituent generations // to be used to limit the extent of sweep in each generation. @@ -3178,7 +3181,7 @@ void CMSConcMarkingTask::bump_global_finger(HeapWord* f) { HeapWord* cur = read; while (f > read) { cur = read; - read = (HeapWord*) Atomic::cmpxchg_ptr(f, &_global_finger, cur); + read = Atomic::cmpxchg(f, &_global_finger, cur); if (cur == read) { // our cas succeeded assert(_global_finger >= f, "protocol consistency"); @@ -3799,7 +3802,7 @@ size_t CMSCollector::preclean_work(bool clean_refs, bool clean_survivor) { bitMapLock()); startTimer(); unsigned int before_count = - GenCollectedHeap::heap()->total_collections(); + CMSHeap::heap()->total_collections(); SurvivorSpacePrecleanClosure sss_cl(this, _span, &_markBitMap, &_markStack, &pam_cl, before_count, CMSYield); @@ -3848,7 +3851,7 @@ size_t CMSCollector::preclean_work(bool clean_refs, bool clean_survivor) { } } - preclean_klasses(&mrias_cl, _cmsGen->freelistLock()); + preclean_cld(&mrias_cl, _cmsGen->freelistLock()); curNumCards = preclean_card_table(_cmsGen, &smoac_cl); cumNumCards += curNumCards; @@ -4067,21 +4070,21 @@ size_t CMSCollector::preclean_card_table(ConcurrentMarkSweepGeneration* old_gen, return cumNumDirtyCards; } -class PrecleanKlassClosure : public KlassClosure { - KlassToOopClosure _cm_klass_closure; +class PrecleanCLDClosure : public CLDClosure { + MetadataAwareOopsInGenClosure* _cm_closure; public: - PrecleanKlassClosure(OopClosure* oop_closure) : _cm_klass_closure(oop_closure) {} - void do_klass(Klass* k) { - if (k->has_accumulated_modified_oops()) { - k->clear_accumulated_modified_oops(); + PrecleanCLDClosure(MetadataAwareOopsInGenClosure* oop_closure) : _cm_closure(oop_closure) {} + void do_cld(ClassLoaderData* cld) { + if (cld->has_accumulated_modified_oops()) { + cld->clear_accumulated_modified_oops(); - _cm_klass_closure.do_klass(k); + _cm_closure->do_cld(cld); } } }; // The freelist lock is needed to prevent asserts, is it really needed? -void CMSCollector::preclean_klasses(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock) { +void CMSCollector::preclean_cld(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock) { cl->set_freelistLock(freelistLock); @@ -4089,8 +4092,8 @@ void CMSCollector::preclean_klasses(MarkRefsIntoAndScanClosure* cl, Mutex* freel // SSS: Add equivalent to ScanMarkedObjectsAgainCarefullyClosure::do_yield_check and should_abort_preclean? // SSS: We should probably check if precleaning should be aborted, at suitable intervals? - PrecleanKlassClosure preclean_klass_closure(cl); - ClassLoaderDataGraph::classes_do(&preclean_klass_closure); + PrecleanCLDClosure preclean_closure(cl); + ClassLoaderDataGraph::cld_do(&preclean_closure); verify_work_stacks_empty(); verify_overflow_empty(); @@ -4102,7 +4105,7 @@ void CMSCollector::checkpointRootsFinal() { // world is stopped at this checkpoint assert(SafepointSynchronize::is_at_safepoint(), "world should be stopped"); - TraceCMSMemoryManagerStats tms(_collectorState,GenCollectedHeap::heap()->gc_cause()); + TraceCMSMemoryManagerStats tms(_collectorState, CMSHeap::heap()->gc_cause()); verify_work_stacks_empty(); verify_overflow_empty(); @@ -4111,16 +4114,16 @@ void CMSCollector::checkpointRootsFinal() { _young_gen->used() / K, _young_gen->capacity() / K); { if (CMSScavengeBeforeRemark) { - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); // Temporarily set flag to false, GCH->do_collection will // expect it to be false and set to true - FlagSetting fl(gch->_is_gc_active, false); + FlagSetting fl(heap->_is_gc_active, false); - gch->do_collection(true, // full (i.e. force, see below) - false, // !clear_all_soft_refs - 0, // size - false, // is_tlab - GenCollectedHeap::YoungGen // type + heap->do_collection(true, // full (i.e. force, see below) + false, // !clear_all_soft_refs + 0, // size + false, // is_tlab + GenCollectedHeap::YoungGen // type ); } FreelistLocker x(this); @@ -4141,7 +4144,7 @@ void CMSCollector::checkpointRootsFinalWork() { ResourceMark rm; HandleMark hm; - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); if (should_unload_classes()) { CodeCache::gc_prologue(); @@ -4161,9 +4164,9 @@ void CMSCollector::checkpointRootsFinalWork() { // or of an indication of whether the scavenge did indeed occur, // we cannot rely on TLAB's having been filled and must do // so here just in case a scavenge did not happen. - gch->ensure_parsability(false); // fill TLAB's, but no need to retire them + heap->ensure_parsability(false); // fill TLAB's, but no need to retire them // Update the saved marks which may affect the root scans. - gch->save_marks(); + heap->save_marks(); print_eden_and_survivor_chunk_arrays(); @@ -4239,7 +4242,7 @@ void CMSCollector::checkpointRootsFinalWork() { _markStack._failed_double = 0; if ((VerifyAfterGC || VerifyDuringGC) && - GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { + CMSHeap::heap()->total_collections() >= VerifyGCStartAt) { verify_after_remark(); } @@ -4250,7 +4253,7 @@ void CMSCollector::checkpointRootsFinalWork() { // Call isAllClear() under bitMapLock assert(_modUnionTable.isAllClear(), "Should be clear by end of the final marking"); - assert(_ct->klass_rem_set()->mod_union_is_clear(), + assert(_ct->cld_rem_set()->mod_union_is_clear(), "Should be clear by end of the final marking"); } @@ -4261,7 +4264,7 @@ void CMSParInitialMarkTask::work(uint worker_id) { // ---------- scan from roots -------------- _timer.start(); - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); ParMarkRefsIntoClosure par_mri_cl(_collector->_span, &(_collector->_markBitMap)); // ---------- young gen roots -------------- @@ -4277,12 +4280,12 @@ void CMSParInitialMarkTask::work(uint worker_id) { CLDToOopClosure cld_closure(&par_mri_cl, true); - gch->cms_process_roots(_strong_roots_scope, - false, // yg was scanned above - GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()), - _collector->should_unload_classes(), - &par_mri_cl, - &cld_closure); + heap->cms_process_roots(_strong_roots_scope, + false, // yg was scanned above + GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()), + _collector->should_unload_classes(), + &par_mri_cl, + &cld_closure); assert(_collector->should_unload_classes() || (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache), "if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops"); @@ -4332,26 +4335,26 @@ class CMSParRemarkTask: public CMSParMarkTask { void do_work_steal(int i, ParMarkRefsIntoAndScanClosure* cl, int* seed); }; -class RemarkKlassClosure : public KlassClosure { - KlassToOopClosure _cm_klass_closure; +class RemarkCLDClosure : public CLDClosure { + CLDToOopClosure _cm_closure; public: - RemarkKlassClosure(OopClosure* oop_closure) : _cm_klass_closure(oop_closure) {} - void do_klass(Klass* k) { - // Check if we have modified any oops in the Klass during the concurrent marking. - if (k->has_accumulated_modified_oops()) { - k->clear_accumulated_modified_oops(); + RemarkCLDClosure(OopClosure* oop_closure) : _cm_closure(oop_closure) {} + void do_cld(ClassLoaderData* cld) { + // Check if we have modified any oops in the CLD during the concurrent marking. + if (cld->has_accumulated_modified_oops()) { + cld->clear_accumulated_modified_oops(); // We could have transfered the current modified marks to the accumulated marks, // like we do with the Card Table to Mod Union Table. But it's not really necessary. - } else if (k->has_modified_oops()) { + } else if (cld->has_modified_oops()) { // Don't clear anything, this info is needed by the next young collection. } else { - // No modified oops in the Klass. + // No modified oops in the ClassLoaderData. return; } // The klass has modified fields, need to scan the klass. - _cm_klass_closure.do_klass(k); + _cm_closure.do_cld(cld); } }; @@ -4386,7 +4389,7 @@ void CMSParRemarkTask::work(uint worker_id) { // ---------- rescan from roots -------------- _timer.start(); - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); ParMarkRefsIntoAndScanClosure par_mrias_cl(_collector, _collector->_span, _collector->ref_processor(), &(_collector->_markBitMap), @@ -4406,12 +4409,12 @@ void CMSParRemarkTask::work(uint worker_id) { // ---------- remaining roots -------------- _timer.reset(); _timer.start(); - gch->cms_process_roots(_strong_roots_scope, - false, // yg was scanned above - GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()), - _collector->should_unload_classes(), - &par_mrias_cl, - NULL); // The dirty klasses will be handled below + heap->cms_process_roots(_strong_roots_scope, + false, // yg was scanned above + GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()), + _collector->should_unload_classes(), + &par_mrias_cl, + NULL); // The dirty klasses will be handled below assert(_collector->should_unload_classes() || (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache), @@ -4439,24 +4442,24 @@ void CMSParRemarkTask::work(uint worker_id) { log_trace(gc, task)("Finished unhandled CLD scanning work in %dth thread: %3.3f sec", worker_id, _timer.seconds()); } - // ---------- dirty klass scanning ---------- + // We might have added oops to ClassLoaderData::_handles during the + // concurrent marking phase. These oops do not always point to newly allocated objects + // that are guaranteed to be kept alive. Hence, + // we do have to revisit the _handles block during the remark phase. + + // ---------- dirty CLD scanning ---------- if (worker_id == 0) { // Single threaded at the moment. _timer.reset(); _timer.start(); // Scan all classes that was dirtied during the concurrent marking phase. - RemarkKlassClosure remark_klass_closure(&par_mrias_cl); - ClassLoaderDataGraph::classes_do(&remark_klass_closure); + RemarkCLDClosure remark_closure(&par_mrias_cl); + ClassLoaderDataGraph::cld_do(&remark_closure); _timer.stop(); - log_trace(gc, task)("Finished dirty klass scanning work in %dth thread: %3.3f sec", worker_id, _timer.seconds()); + log_trace(gc, task)("Finished dirty CLD scanning work in %dth thread: %3.3f sec", worker_id, _timer.seconds()); } - // We might have added oops to ClassLoaderData::_handles during the - // concurrent marking phase. These oops point to newly allocated objects - // that are guaranteed to be kept alive. Either by the direct allocation - // code, or when the young collector processes the roots. Hence, - // we don't have to revisit the _handles block during the remark phase. // ---------- rescan dirty cards ------------ _timer.reset(); @@ -4838,8 +4841,8 @@ initialize_sequential_subtasks_for_young_gen_rescan(int n_threads) { // Parallel version of remark void CMSCollector::do_remark_parallel() { - GenCollectedHeap* gch = GenCollectedHeap::heap(); - WorkGang* workers = gch->workers(); + CMSHeap* heap = CMSHeap::heap(); + WorkGang* workers = heap->workers(); assert(workers != NULL, "Need parallel worker threads."); // Choose to use the number of GC workers most recently set // into "active_workers". @@ -4855,7 +4858,7 @@ void CMSCollector::do_remark_parallel() { // the younger_gen cards, so we shouldn't call the following else // the verification code as well as subsequent younger_refs_iterate // code would get confused. XXX - // gch->rem_set()->prepare_for_younger_refs_iterate(true); // parallel + // heap->rem_set()->prepare_for_younger_refs_iterate(true); // parallel // The young gen rescan work will not be done as part of // process_roots (which currently doesn't know how to @@ -4897,7 +4900,7 @@ void CMSCollector::do_remark_parallel() { void CMSCollector::do_remark_non_parallel() { ResourceMark rm; HandleMark hm; - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); ReferenceProcessorMTDiscoveryMutator mt(ref_processor(), false); MarkRefsIntoAndScanClosure @@ -4938,7 +4941,7 @@ void CMSCollector::do_remark_non_parallel() { } } if (VerifyDuringGC && - GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { + CMSHeap::heap()->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification Universe::verify(); } @@ -4947,15 +4950,15 @@ void CMSCollector::do_remark_non_parallel() { verify_work_stacks_empty(); - gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. + heap->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. StrongRootsScope srs(1); - gch->cms_process_roots(&srs, - true, // young gen as roots - GenCollectedHeap::ScanningOption(roots_scanning_options()), - should_unload_classes(), - &mrias_cl, - NULL); // The dirty klasses will be handled below + heap->cms_process_roots(&srs, + true, // young gen as roots + GenCollectedHeap::ScanningOption(roots_scanning_options()), + should_unload_classes(), + &mrias_cl, + NULL); // The dirty klasses will be handled below assert(should_unload_classes() || (roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache), @@ -4981,23 +4984,21 @@ void CMSCollector::do_remark_non_parallel() { verify_work_stacks_empty(); } + // We might have added oops to ClassLoaderData::_handles during the + // concurrent marking phase. These oops do not point to newly allocated objects + // that are guaranteed to be kept alive. Hence, + // we do have to revisit the _handles block during the remark phase. { - GCTraceTime(Trace, gc, phases) t("Dirty Klass Scan", _gc_timer_cm); + GCTraceTime(Trace, gc, phases) t("Dirty CLD Scan", _gc_timer_cm); verify_work_stacks_empty(); - RemarkKlassClosure remark_klass_closure(&mrias_cl); - ClassLoaderDataGraph::classes_do(&remark_klass_closure); + RemarkCLDClosure remark_closure(&mrias_cl); + ClassLoaderDataGraph::cld_do(&remark_closure); verify_work_stacks_empty(); } - // We might have added oops to ClassLoaderData::_handles during the - // concurrent marking phase. These oops point to newly allocated objects - // that are guaranteed to be kept alive. Either by the direct allocation - // code, or when the young collector processes the roots. Hence, - // we don't have to revisit the _handles block during the remark phase. - verify_work_stacks_empty(); // Restore evacuated mark words, if any, used for overflow list links restore_preserved_marks_if_any(); @@ -5149,8 +5150,8 @@ void CMSRefProcTaskProxy::do_work_steal(int i, void CMSRefProcTaskExecutor::execute(ProcessTask& task) { - GenCollectedHeap* gch = GenCollectedHeap::heap(); - WorkGang* workers = gch->workers(); + CMSHeap* heap = CMSHeap::heap(); + WorkGang* workers = heap->workers(); assert(workers != NULL, "Need parallel worker threads."); CMSRefProcTaskProxy rp_task(task, &_collector, _collector.ref_processor()->span(), @@ -5162,8 +5163,8 @@ void CMSRefProcTaskExecutor::execute(ProcessTask& task) void CMSRefProcTaskExecutor::execute(EnqueueTask& task) { - GenCollectedHeap* gch = GenCollectedHeap::heap(); - WorkGang* workers = gch->workers(); + CMSHeap* heap = CMSHeap::heap(); + WorkGang* workers = heap->workers(); assert(workers != NULL, "Need parallel worker threads."); CMSRefEnqueueTaskProxy enq_task(task); workers->run_task(&enq_task); @@ -5180,15 +5181,17 @@ void CMSCollector::refProcessingWork() { rp->setup_policy(false); verify_work_stacks_empty(); - CMSKeepAliveClosure cmsKeepAliveClosure(this, _span, &_markBitMap, - &_markStack, false /* !preclean */); - CMSDrainMarkingStackClosure cmsDrainMarkingStackClosure(this, - _span, &_markBitMap, &_markStack, - &cmsKeepAliveClosure, false /* !preclean */); ReferenceProcessorPhaseTimes pt(_gc_timer_cm, rp->num_q()); { GCTraceTime(Debug, gc, phases) t("Reference Processing", _gc_timer_cm); + // Setup keep_alive and complete closures. + CMSKeepAliveClosure cmsKeepAliveClosure(this, _span, &_markBitMap, + &_markStack, false /* !preclean */); + CMSDrainMarkingStackClosure cmsDrainMarkingStackClosure(this, + _span, &_markBitMap, &_markStack, + &cmsKeepAliveClosure, false /* !preclean */); + ReferenceProcessorStats stats; if (rp->processing_is_mt()) { // Set the degree of MT here. If the discovery is done MT, there @@ -5196,9 +5199,9 @@ void CMSCollector::refProcessingWork() { // and a different number of discovered lists may have Ref objects. // That is OK as long as the Reference lists are balanced (see // balance_all_queues() and balance_queues()). - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); uint active_workers = ParallelGCThreads; - WorkGang* workers = gch->workers(); + WorkGang* workers = heap->workers(); if (workers != NULL) { active_workers = workers->active_workers(); // The expectation is that active_workers will have already @@ -5227,6 +5230,11 @@ void CMSCollector::refProcessingWork() { // This is the point where the entire marking should have completed. verify_work_stacks_empty(); + { + GCTraceTime(Debug, gc, phases) t("Weak Processing", _gc_timer_cm); + WeakProcessor::weak_oops_do(&_is_alive_closure, &do_nothing_cl); + } + if (should_unload_classes()) { { GCTraceTime(Debug, gc, phases) t("Class Unloading", _gc_timer_cm); @@ -5306,7 +5314,7 @@ void CMSCollector::sweep() { verify_work_stacks_empty(); verify_overflow_empty(); increment_sweep_count(); - TraceCMSMemoryManagerStats tms(_collectorState,GenCollectedHeap::heap()->gc_cause()); + TraceCMSMemoryManagerStats tms(_collectorState, CMSHeap::heap()->gc_cause()); _inter_sweep_timer.stop(); _inter_sweep_estimate.sample(_inter_sweep_timer.seconds()); @@ -5379,9 +5387,9 @@ void CMSCollector::sweep() { // this generation. If such a promotion may still fail, // the flag will be set again when a young collection is // attempted. - GenCollectedHeap* gch = GenCollectedHeap::heap(); - gch->clear_incremental_collection_failed(); // Worth retrying as fresh space may have been freed up - gch->update_full_collections_completed(_collection_count_start); + CMSHeap* heap = CMSHeap::heap(); + heap->clear_incremental_collection_failed(); // Worth retrying as fresh space may have been freed up + heap->update_full_collections_completed(_collection_count_start); } // FIX ME!!! Looks like this belongs in CFLSpace, with @@ -5416,7 +5424,7 @@ void ConcurrentMarkSweepGeneration::update_gc_stats(Generation* current_generati bool full) { // If the young generation has been collected, gather any statistics // that are of interest at this point. - bool current_is_young = GenCollectedHeap::heap()->is_young_gen(current_generation); + bool current_is_young = CMSHeap::heap()->is_young_gen(current_generation); if (!full && current_is_young) { // Gather statistics on the young generation collection. collector()->stats().record_gc0_end(used()); @@ -6189,7 +6197,7 @@ size_t SurvivorSpacePrecleanClosure::do_object_careful(oop p) { do_yield_check(); } unsigned int after_count = - GenCollectedHeap::heap()->total_collections(); + CMSHeap::heap()->total_collections(); bool abort = (_before_count != after_count) || _collector->should_abort_preclean(); return abort ? 0 : size; @@ -7853,7 +7861,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num, return false; } // Grab the entire list; we'll put back a suffix - oop prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list)); + oop prefix = cast_to_oop(Atomic::xchg((oopDesc*)BUSY, &_overflow_list)); Thread* tid = Thread::current(); // Before "no_of_gc_threads" was introduced CMSOverflowSpinCount was // set to ParallelGCThreads. @@ -7868,7 +7876,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num, return false; } else if (_overflow_list != BUSY) { // Try and grab the prefix - prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list)); + prefix = cast_to_oop(Atomic::xchg((oopDesc*)BUSY, &_overflow_list)); } } // If the list was found to be empty, or we spun long @@ -7881,7 +7889,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num, if (prefix == NULL) { // Write back the NULL in case we overwrote it with BUSY above // and it is still the same value. - (void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY); + Atomic::cmpxchg((oopDesc*)NULL, &_overflow_list, (oopDesc*)BUSY); } return false; } @@ -7896,7 +7904,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num, // Write back the NULL in lieu of the BUSY we wrote // above, if it is still the same value. if (_overflow_list == BUSY) { - (void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY); + Atomic::cmpxchg((oopDesc*)NULL, &_overflow_list, (oopDesc*)BUSY); } } else { // Chop off the suffix and return it to the global list. @@ -7912,7 +7920,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num, bool attached = false; while (observed_overflow_list == BUSY || observed_overflow_list == NULL) { observed_overflow_list = - (oop) Atomic::cmpxchg_ptr(suffix_head, &_overflow_list, cur_overflow_list); + Atomic::cmpxchg((oopDesc*)suffix_head, &_overflow_list, (oopDesc*)cur_overflow_list); if (cur_overflow_list == observed_overflow_list) { attached = true; break; @@ -7937,7 +7945,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num, } // ... and try to place spliced list back on overflow_list ... observed_overflow_list = - (oop) Atomic::cmpxchg_ptr(suffix_head, &_overflow_list, cur_overflow_list); + Atomic::cmpxchg((oopDesc*)suffix_head, &_overflow_list, (oopDesc*)cur_overflow_list); } while (cur_overflow_list != observed_overflow_list); // ... until we have succeeded in doing so. } @@ -7958,7 +7966,7 @@ bool CMSCollector::par_take_from_overflow_list(size_t num, } #ifndef PRODUCT assert(_num_par_pushes >= n, "Too many pops?"); - Atomic::add_ptr(-(intptr_t)n, &_num_par_pushes); + Atomic::sub(n, &_num_par_pushes); #endif return true; } @@ -7974,7 +7982,7 @@ void CMSCollector::push_on_overflow_list(oop p) { // Multi-threaded; use CAS to prepend to overflow list void CMSCollector::par_push_on_overflow_list(oop p) { - NOT_PRODUCT(Atomic::inc_ptr(&_num_par_pushes);) + NOT_PRODUCT(Atomic::inc(&_num_par_pushes);) assert(oopDesc::is_oop(p), "Not an oop"); par_preserve_mark_if_necessary(p); oop observed_overflow_list = _overflow_list; @@ -7987,7 +7995,7 @@ void CMSCollector::par_push_on_overflow_list(oop p) { p->set_mark(NULL); } observed_overflow_list = - (oop) Atomic::cmpxchg_ptr(p, &_overflow_list, cur_overflow_list); + Atomic::cmpxchg((oopDesc*)p, &_overflow_list, (oopDesc*)cur_overflow_list); } while (cur_overflow_list != observed_overflow_list); } #undef BUSY diff --git a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.hpp b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.hpp index 978310aaade..aebaae75705 100644 --- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.hpp +++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.hpp @@ -777,7 +777,7 @@ class CMSCollector: public CHeapObj { // Does precleaning work, returning a quantity indicative of // the amount of "useful work" done. size_t preclean_work(bool clean_refs, bool clean_survivors); - void preclean_klasses(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock); + void preclean_cld(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock); void abortable_preclean(); // Preclean while looking for possible abort void initialize_sequential_subtasks_for_young_gen_rescan(int i); // Helper function for above; merge-sorts the per-thread plab samples diff --git a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.inline.hpp b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.inline.hpp index 503ef69eff0..ca61c8fd45c 100644 --- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.inline.hpp +++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.inline.hpp @@ -25,13 +25,13 @@ #ifndef SHARE_VM_GC_CMS_CONCURRENTMARKSWEEPGENERATION_INLINE_HPP #define SHARE_VM_GC_CMS_CONCURRENTMARKSWEEPGENERATION_INLINE_HPP +#include "gc/cms/cmsHeap.hpp" #include "gc/cms/cmsLockVerifier.hpp" #include "gc/cms/compactibleFreeListSpace.hpp" #include "gc/cms/concurrentMarkSweepGeneration.hpp" #include "gc/cms/concurrentMarkSweepThread.hpp" #include "gc/cms/parNewGeneration.hpp" #include "gc/shared/gcUtil.hpp" -#include "gc/shared/genCollectedHeap.hpp" #include "utilities/align.hpp" #include "utilities/bitMap.inline.hpp" @@ -256,7 +256,7 @@ inline bool CMSCollector::should_abort_preclean() const { // scavenge is done or foreground GC wants to take over collection return _collectorState == AbortablePreclean && (_abort_preclean || _foregroundGCIsActive || - GenCollectedHeap::heap()->incremental_collection_will_fail(true /* consult_young */)); + CMSHeap::heap()->incremental_collection_will_fail(true /* consult_young */)); } inline size_t CMSCollector::get_eden_used() const { diff --git a/src/hotspot/share/gc/cms/concurrentMarkSweepThread.cpp b/src/hotspot/share/gc/cms/concurrentMarkSweepThread.cpp index 43a32e913e8..a4de148bc1a 100644 --- a/src/hotspot/share/gc/cms/concurrentMarkSweepThread.cpp +++ b/src/hotspot/share/gc/cms/concurrentMarkSweepThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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 @@ -24,10 +24,10 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" +#include "gc/cms/cmsHeap.hpp" #include "gc/cms/concurrentMarkSweepGeneration.inline.hpp" #include "gc/cms/concurrentMarkSweepThread.hpp" #include "gc/shared/gcId.hpp" -#include "gc/shared/genCollectedHeap.hpp" #include "oops/oop.inline.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.hpp" @@ -225,7 +225,7 @@ void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) { // Wait time in millis or 0 value representing infinite wait for a scavenge assert(t_millis >= 0, "Wait time for scavenge should be 0 or positive"); - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); double start_time_secs = os::elapsedTime(); double end_time_secs = start_time_secs + (t_millis / ((double) MILLIUNITS)); @@ -233,7 +233,7 @@ void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) { unsigned int before_count; { MutexLockerEx hl(Heap_lock, Mutex::_no_safepoint_check_flag); - before_count = gch->total_collections(); + before_count = heap->total_collections(); } unsigned int loop_count = 0; @@ -279,7 +279,7 @@ void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) { unsigned int after_count; { MutexLockerEx hl(Heap_lock, Mutex::_no_safepoint_check_flag); - after_count = gch->total_collections(); + after_count = heap->total_collections(); } if(before_count != after_count) { diff --git a/src/hotspot/share/gc/cms/parCardTableModRefBS.cpp b/src/hotspot/share/gc/cms/parCardTableModRefBS.cpp index 4456fe6fc7d..085b94cb388 100644 --- a/src/hotspot/share/gc/cms/parCardTableModRefBS.cpp +++ b/src/hotspot/share/gc/cms/parCardTableModRefBS.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2017, 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,10 +23,10 @@ */ #include "precompiled.hpp" +#include "gc/cms/cmsHeap.hpp" #include "gc/shared/cardTableModRefBS.hpp" #include "gc/shared/cardTableRS.hpp" #include "gc/shared/collectedHeap.hpp" -#include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/space.inline.hpp" #include "memory/allocation.inline.hpp" #include "memory/virtualspace.hpp" @@ -394,7 +394,7 @@ get_LNC_array_for_space(Space* sp, // Do a dirty read here. If we pass the conditional then take the rare // event lock and do the read again in case some other thread had already // succeeded and done the resize. - int cur_collection = GenCollectedHeap::heap()->total_collections(); + int cur_collection = CMSHeap::heap()->total_collections(); // Updated _last_LNC_resizing_collection[i] must not be visible before // _lowest_non_clean and friends are visible. Therefore use acquire/release // to guarantee this on non TSO architecures. diff --git a/src/hotspot/share/gc/cms/parNewGeneration.cpp b/src/hotspot/share/gc/cms/parNewGeneration.cpp index 5d651e0507e..74bb6c96e3f 100644 --- a/src/hotspot/share/gc/cms/parNewGeneration.cpp +++ b/src/hotspot/share/gc/cms/parNewGeneration.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc/cms/cmsHeap.hpp" #include "gc/cms/compactibleFreeListSpace.hpp" #include "gc/cms/concurrentMarkSweepGeneration.hpp" #include "gc/cms/parNewGeneration.inline.hpp" @@ -45,6 +46,7 @@ #include "gc/shared/spaceDecorator.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskqueue.inline.hpp" +#include "gc/shared/weakProcessor.hpp" #include "gc/shared/workgroup.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" @@ -124,7 +126,7 @@ bool ParScanThreadState::should_be_partially_scanned(oop new_obj, oop old_obj) c void ParScanThreadState::scan_partial_array_and_push_remainder(oop old) { assert(old->is_objArray(), "must be obj array"); assert(old->is_forwarded(), "must be forwarded"); - assert(GenCollectedHeap::heap()->is_in_reserved(old), "must be in heap."); + assert(CMSHeap::heap()->is_in_reserved(old), "must be in heap."); assert(!old_gen()->is_in(old), "must be in young generation."); objArrayOop obj = objArrayOop(old->forwardee()); @@ -205,9 +207,9 @@ bool ParScanThreadState::take_from_overflow_stack() { for (size_t i = 0; i != num_take_elems; i++) { oop cur = of_stack->pop(); oop obj_to_push = cur->forwardee(); - assert(GenCollectedHeap::heap()->is_in_reserved(cur), "Should be in heap"); + assert(CMSHeap::heap()->is_in_reserved(cur), "Should be in heap"); assert(!old_gen()->is_in_reserved(cur), "Should be in young gen"); - assert(GenCollectedHeap::heap()->is_in_reserved(obj_to_push), "Should be in heap"); + assert(CMSHeap::heap()->is_in_reserved(obj_to_push), "Should be in heap"); if (should_be_partially_scanned(obj_to_push, cur)) { assert(arrayOop(cur)->length() == 0, "entire array remaining to be scanned"); obj_to_push = cur; @@ -493,7 +495,7 @@ void ParScanThreadStateSet::flush() { ParScanClosure::ParScanClosure(ParNewGeneration* g, ParScanThreadState* par_scan_state) : - OopsInKlassOrGenClosure(g), _par_scan_state(par_scan_state), _g(g) { + OopsInClassLoaderDataOrGenClosure(g), _par_scan_state(par_scan_state), _g(g) { _boundary = _g->reserved().end(); } @@ -590,7 +592,7 @@ ParNewGenTask::ParNewGenTask(ParNewGeneration* young_gen, {} void ParNewGenTask::work(uint worker_id) { - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); // Since this is being done in a separate thread, need new resource // and handle marks. ResourceMark rm; @@ -601,14 +603,11 @@ void ParNewGenTask::work(uint worker_id) { par_scan_state.set_young_old_boundary(_young_old_boundary); - KlassScanClosure klass_scan_closure(&par_scan_state.to_space_root_closure(), - gch->rem_set()->klass_rem_set()); - CLDToKlassAndOopClosure cld_scan_closure(&klass_scan_closure, - &par_scan_state.to_space_root_closure(), - false); + CLDScanClosure cld_scan_closure(&par_scan_state.to_space_root_closure(), + heap->rem_set()->cld_rem_set()->accumulate_modified_oops()); par_scan_state.start_strong_roots(); - gch->young_process_roots(_strong_roots_scope, + heap->young_process_roots(_strong_roots_scope, &par_scan_state.to_space_root_closure(), &par_scan_state.older_gen_closure(), &cld_scan_closure); @@ -690,7 +689,7 @@ void /*ParNewGeneration::*/ParKeepAliveClosure::do_oop_work(T* p) { _par_cl->do_oop_nv(p); - if (GenCollectedHeap::heap()->is_in_reserved(p)) { + if (CMSHeap::heap()->is_in_reserved(p)) { oop obj = oopDesc::load_decode_heap_oop_not_null(p); _rs->write_ref_field_gc_par(p, obj); } @@ -717,7 +716,7 @@ void /*ParNewGeneration::*/KeepAliveClosure::do_oop_work(T* p) { _cl->do_oop_nv(p); - if (GenCollectedHeap::heap()->is_in_reserved(p)) { + if (CMSHeap::heap()->is_in_reserved(p)) { oop obj = oopDesc::load_decode_heap_oop_not_null(p); _rs->write_ref_field_gc_par(p, obj); } @@ -807,7 +806,7 @@ public: }; void ParNewRefProcTaskExecutor::execute(ProcessTask& task) { - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* gch = CMSHeap::heap(); WorkGang* workers = gch->workers(); assert(workers != NULL, "Need parallel worker threads."); _state_set.reset(workers->active_workers(), _young_gen.promotion_failed()); @@ -819,7 +818,7 @@ void ParNewRefProcTaskExecutor::execute(ProcessTask& task) { } void ParNewRefProcTaskExecutor::execute(EnqueueTask& task) { - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* gch = CMSHeap::heap(); WorkGang* workers = gch->workers(); assert(workers != NULL, "Need parallel worker threads."); ParNewRefEnqueueTaskProxy enq_task(task); @@ -828,8 +827,8 @@ void ParNewRefProcTaskExecutor::execute(EnqueueTask& task) { void ParNewRefProcTaskExecutor::set_single_threaded_mode() { _state_set.flush(); - GenCollectedHeap* gch = GenCollectedHeap::heap(); - gch->save_marks(); + CMSHeap* heap = CMSHeap::heap(); + heap->save_marks(); } ScanClosureWithParBarrier:: @@ -838,10 +837,10 @@ ScanClosureWithParBarrier(ParNewGeneration* g, bool gc_barrier) : { } EvacuateFollowersClosureGeneral:: -EvacuateFollowersClosureGeneral(GenCollectedHeap* gch, +EvacuateFollowersClosureGeneral(CMSHeap* heap, OopsInGenClosure* cur, OopsInGenClosure* older) : - _gch(gch), + _heap(heap), _scan_cur_or_nonheap(cur), _scan_older(older) { } @@ -849,15 +848,15 @@ void EvacuateFollowersClosureGeneral::do_void() { do { // Beware: this call will lead to closure applications via virtual // calls. - _gch->oop_since_save_marks_iterate(GenCollectedHeap::YoungGen, - _scan_cur_or_nonheap, - _scan_older); - } while (!_gch->no_allocs_since_save_marks()); + _heap->oop_since_save_marks_iterate(GenCollectedHeap::YoungGen, + _scan_cur_or_nonheap, + _scan_older); + } while (!_heap->no_allocs_since_save_marks()); } // A Generation that does parallel young-gen collection. -void ParNewGeneration::handle_promotion_failed(GenCollectedHeap* gch, ParScanThreadStateSet& thread_state_set) { +void ParNewGeneration::handle_promotion_failed(CMSHeap* gch, ParScanThreadStateSet& thread_state_set) { assert(_promo_failure_scan_stack.is_empty(), "post condition"); _promo_failure_scan_stack.clear(true); // Clear cached segments. @@ -886,7 +885,7 @@ void ParNewGeneration::collect(bool full, bool is_tlab) { assert(full || size > 0, "otherwise we don't want to collect"); - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* gch = CMSHeap::heap(); _gc_timer->register_gc_start(); @@ -1001,6 +1000,14 @@ void ParNewGeneration::collect(bool full, _gc_tracer.report_tenuring_threshold(tenuring_threshold()); pt.print_all_references(); + assert(gch->no_allocs_since_save_marks(), "evacuation should be done at this point"); + + WeakProcessor::weak_oops_do(&is_alive, &keep_alive); + + // Verify that the usage of keep_alive only forwarded + // the oops and did not find anything new to copy. + assert(gch->no_allocs_since_save_marks(), "unexpectedly copied objects"); + if (!promotion_failed()) { // Swap the survivor spaces. eden()->clear(SpaceDecorator::Mangle); @@ -1067,7 +1074,7 @@ void ParNewGeneration::collect(bool full, } size_t ParNewGeneration::desired_plab_sz() { - return _plab_stats.desired_plab_sz(GenCollectedHeap::heap()->workers()->active_workers()); + return _plab_stats.desired_plab_sz(CMSHeap::heap()->workers()->active_workers()); } static int sum; @@ -1171,7 +1178,7 @@ oop ParNewGeneration::copy_to_survivor_space(ParScanThreadState* par_scan_state, } else { // Is in to-space; do copying ourselves. Copy::aligned_disjoint_words((HeapWord*)old, (HeapWord*)new_obj, sz); - assert(GenCollectedHeap::heap()->is_in_reserved(new_obj), "illegal forwarding pointer value."); + assert(CMSHeap::heap()->is_in_reserved(new_obj), "illegal forwarding pointer value."); forward_ptr = old->forward_to_atomic(new_obj); // Restore the mark word copied above. new_obj->set_mark(m); @@ -1281,7 +1288,7 @@ void ParNewGeneration::push_on_overflow_list(oop from_space_obj, ParScanThreadSt // XXX This is horribly inefficient when a promotion failure occurs // and should be fixed. XXX FIX ME !!! #ifndef PRODUCT - Atomic::inc_ptr(&_num_par_pushes); + Atomic::inc(&_num_par_pushes); assert(_num_par_pushes > 0, "Tautology"); #endif if (from_space_obj->forwardee() == from_space_obj) { @@ -1299,7 +1306,7 @@ void ParNewGeneration::push_on_overflow_list(oop from_space_obj, ParScanThreadSt from_space_obj->set_klass_to_list_ptr(NULL); } observed_overflow_list = - (oop)Atomic::cmpxchg_ptr(from_space_obj, &_overflow_list, cur_overflow_list); + Atomic::cmpxchg((oopDesc*)from_space_obj, &_overflow_list, (oopDesc*)cur_overflow_list); } while (cur_overflow_list != observed_overflow_list); } } @@ -1342,7 +1349,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan if (_overflow_list == NULL) return false; // Otherwise, there was something there; try claiming the list. - oop prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list)); + oop prefix = cast_to_oop(Atomic::xchg((oopDesc*)BUSY, &_overflow_list)); // Trim off a prefix of at most objsFromOverflow items Thread* tid = Thread::current(); size_t spin_count = ParallelGCThreads; @@ -1356,7 +1363,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan return false; } else if (_overflow_list != BUSY) { // try and grab the prefix - prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list)); + prefix = cast_to_oop(Atomic::xchg((oopDesc*)BUSY, &_overflow_list)); } } if (prefix == NULL || prefix == BUSY) { @@ -1364,7 +1371,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan if (prefix == NULL) { // Write back the NULL in case we overwrote it with BUSY above // and it is still the same value. - (void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY); + (void) Atomic::cmpxchg((oopDesc*)NULL, &_overflow_list, (oopDesc*)BUSY); } return false; } @@ -1383,7 +1390,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan // Write back the NULL in lieu of the BUSY we wrote // above and it is still the same value. if (_overflow_list == BUSY) { - (void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY); + (void) Atomic::cmpxchg((oopDesc*)NULL, &_overflow_list, (oopDesc*)BUSY); } } else { assert(suffix != BUSY, "Error"); @@ -1397,7 +1404,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan bool attached = false; while (observed_overflow_list == BUSY || observed_overflow_list == NULL) { observed_overflow_list = - (oop) Atomic::cmpxchg_ptr(suffix, &_overflow_list, cur_overflow_list); + Atomic::cmpxchg((oopDesc*)suffix, &_overflow_list, (oopDesc*)cur_overflow_list); if (cur_overflow_list == observed_overflow_list) { attached = true; break; @@ -1423,7 +1430,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan last->set_klass_to_list_ptr(NULL); } observed_overflow_list = - (oop)Atomic::cmpxchg_ptr(suffix, &_overflow_list, cur_overflow_list); + Atomic::cmpxchg((oopDesc*)suffix, &_overflow_list, (oopDesc*)cur_overflow_list); } while (cur_overflow_list != observed_overflow_list); } } @@ -1455,7 +1462,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan TASKQUEUE_STATS_ONLY(par_scan_state->note_overflow_refill(n)); #ifndef PRODUCT assert(_num_par_pushes >= n, "Too many pops?"); - Atomic::add_ptr(-(intptr_t)n, &_num_par_pushes); + Atomic::sub(n, &_num_par_pushes); #endif return true; } @@ -1478,3 +1485,9 @@ void ParNewGeneration::ref_processor_init() { const char* ParNewGeneration::name() const { return "par new generation"; } + +void ParNewGeneration::restore_preserved_marks() { + SharedRestorePreservedMarksTaskExecutor task_executor(CMSHeap::heap()->workers()); + _preserved_marks_set.restore(&task_executor); +} + diff --git a/src/hotspot/share/gc/cms/parNewGeneration.hpp b/src/hotspot/share/gc/cms/parNewGeneration.hpp index 0576e05cebd..a27c7c36c43 100644 --- a/src/hotspot/share/gc/cms/parNewGeneration.hpp +++ b/src/hotspot/share/gc/cms/parNewGeneration.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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 @@ -35,6 +35,7 @@ #include "memory/padded.hpp" class ChunkArray; +class CMSHeap; class ParScanWithoutBarrierClosure; class ParScanWithBarrierClosure; class ParRootScanWithoutBarrierClosure; @@ -259,11 +260,11 @@ class KeepAliveClosure: public DefNewGeneration::KeepAliveClosure { class EvacuateFollowersClosureGeneral: public VoidClosure { private: - GenCollectedHeap* _gch; + CMSHeap* _heap; OopsInGenClosure* _scan_cur_or_nonheap; OopsInGenClosure* _scan_older; public: - EvacuateFollowersClosureGeneral(GenCollectedHeap* gch, + EvacuateFollowersClosureGeneral(CMSHeap* heap, OopsInGenClosure* cur, OopsInGenClosure* older); virtual void do_void(); @@ -336,7 +337,7 @@ class ParNewGeneration: public DefNewGeneration { static oop real_forwardee_slow(oop obj); static void waste_some_time(); - void handle_promotion_failed(GenCollectedHeap* gch, ParScanThreadStateSet& thread_state_set); + void handle_promotion_failed(CMSHeap* gch, ParScanThreadStateSet& thread_state_set); protected: @@ -345,6 +346,8 @@ class ParNewGeneration: public DefNewGeneration { bool survivor_overflow() { return _survivor_overflow; } void set_survivor_overflow(bool v) { _survivor_overflow = v; } + void restore_preserved_marks(); + public: ParNewGeneration(ReservedSpace rs, size_t initial_byte_size); diff --git a/src/hotspot/share/gc/cms/parOopClosures.hpp b/src/hotspot/share/gc/cms/parOopClosures.hpp index daf95f65785..87b5d98d975 100644 --- a/src/hotspot/share/gc/cms/parOopClosures.hpp +++ b/src/hotspot/share/gc/cms/parOopClosures.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2017, 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 @@ -37,7 +37,7 @@ typedef Padded ObjToScanQueue; typedef GenericTaskQueueSet ObjToScanQueueSet; class ParallelTaskTerminator; -class ParScanClosure: public OopsInKlassOrGenClosure { +class ParScanClosure: public OopsInClassLoaderDataOrGenClosure { protected: ParScanThreadState* _par_scan_state; ParNewGeneration* _g; diff --git a/src/hotspot/share/gc/cms/parOopClosures.inline.hpp b/src/hotspot/share/gc/cms/parOopClosures.inline.hpp index 12092b62be9..a24f004d45a 100644 --- a/src/hotspot/share/gc/cms/parOopClosures.inline.hpp +++ b/src/hotspot/share/gc/cms/parOopClosures.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2017, 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 @@ -25,10 +25,10 @@ #ifndef SHARE_VM_GC_CMS_PAROOPCLOSURES_INLINE_HPP #define SHARE_VM_GC_CMS_PAROOPCLOSURES_INLINE_HPP +#include "gc/cms/cmsHeap.hpp" #include "gc/cms/parNewGeneration.hpp" #include "gc/cms/parOopClosures.hpp" #include "gc/shared/cardTableRS.hpp" -#include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/genOopClosures.inline.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" @@ -72,9 +72,9 @@ template inline void ParScanClosure::do_oop_work(T* p, bool gc_barrier, bool root_scan) { - assert((!GenCollectedHeap::heap()->is_in_reserved(p) || + assert((!CMSHeap::heap()->is_in_reserved(p) || generation()->is_in_reserved(p)) - && (GenCollectedHeap::heap()->is_young_gen(generation()) || gc_barrier), + && (CMSHeap::heap()->is_young_gen(generation()) || gc_barrier), "The gen must be right, and we must be doing the barrier " "in older generations."); T heap_oop = oopDesc::load_heap_oop(p); @@ -85,8 +85,8 @@ inline void ParScanClosure::do_oop_work(T* p, if (_g->to()->is_in_reserved(obj)) { Log(gc) log; log.error("Scanning field (" PTR_FORMAT ") twice?", p2i(p)); - GenCollectedHeap* gch = GenCollectedHeap::heap(); - Space* sp = gch->space_containing(p); + CMSHeap* heap = CMSHeap::heap(); + Space* sp = heap->space_containing(p); oop obj = oop(sp->block_start(p)); assert((HeapWord*)obj < (HeapWord*)p, "Error"); log.error("Object: " PTR_FORMAT, p2i((void *)obj)); @@ -96,7 +96,7 @@ inline void ParScanClosure::do_oop_work(T* p, log.error("-----"); log.error("Heap:"); log.error("-----"); - gch->print_on(&ls); + heap->print_on(&ls); ShouldNotReachHere(); } #endif @@ -126,8 +126,8 @@ inline void ParScanClosure::do_oop_work(T* p, (void)_par_scan_state->trim_queues(10 * ParallelGCThreads); } } - if (is_scanning_a_klass()) { - do_klass_barrier(); + if (is_scanning_a_cld()) { + do_cld_barrier(); } else if (gc_barrier) { // Now call parent closure par_do_barrier(p); diff --git a/src/hotspot/share/gc/cms/vmCMSOperations.cpp b/src/hotspot/share/gc/cms/vmCMSOperations.cpp index 3aa8a0ccd6b..1c2e6a51d10 100644 --- a/src/hotspot/share/gc/cms/vmCMSOperations.cpp +++ b/src/hotspot/share/gc/cms/vmCMSOperations.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, 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,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc/cms/cmsHeap.hpp" #include "gc/cms/concurrentMarkSweepGeneration.inline.hpp" #include "gc/cms/concurrentMarkSweepThread.hpp" #include "gc/cms/vmCMSOperations.hpp" @@ -39,19 +40,19 @@ ////////////////////////////////////////////////////////// void VM_CMS_Operation::verify_before_gc() { if (VerifyBeforeGC && - GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { + CMSHeap::heap()->total_collections() >= VerifyGCStartAt) { GCTraceTime(Info, gc, phases, verify) tm("Verify Before", _collector->_gc_timer_cm); HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); - GenCollectedHeap::heap()->prepare_for_verify(); + CMSHeap::heap()->prepare_for_verify(); Universe::verify(); } } void VM_CMS_Operation::verify_after_gc() { if (VerifyAfterGC && - GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { + CMSHeap::heap()->total_collections() >= VerifyGCStartAt) { GCTraceTime(Info, gc, phases, verify) tm("Verify After", _collector->_gc_timer_cm); HandleMark hm; FreelistLocker x(_collector); @@ -112,13 +113,13 @@ void VM_CMS_Initial_Mark::doit() { _collector->_gc_timer_cm->register_gc_pause_start("Initial Mark"); - GenCollectedHeap* gch = GenCollectedHeap::heap(); - GCCauseSetter gccs(gch, GCCause::_cms_initial_mark); + CMSHeap* heap = CMSHeap::heap(); + GCCauseSetter gccs(heap, GCCause::_cms_initial_mark); VM_CMS_Operation::verify_before_gc(); IsGCActiveMark x; // stop-world GC active - _collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsInitial, gch->gc_cause()); + _collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsInitial, heap->gc_cause()); VM_CMS_Operation::verify_after_gc(); @@ -140,13 +141,13 @@ void VM_CMS_Final_Remark::doit() { _collector->_gc_timer_cm->register_gc_pause_start("Final Mark"); - GenCollectedHeap* gch = GenCollectedHeap::heap(); - GCCauseSetter gccs(gch, GCCause::_cms_final_remark); + CMSHeap* heap = CMSHeap::heap(); + GCCauseSetter gccs(heap, GCCause::_cms_final_remark); VM_CMS_Operation::verify_before_gc(); IsGCActiveMark x; // stop-world GC active - _collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsFinal, gch->gc_cause()); + _collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsFinal, heap->gc_cause()); VM_CMS_Operation::verify_after_gc(); @@ -162,8 +163,8 @@ void VM_GenCollectFullConcurrent::doit() { assert(Thread::current()->is_VM_thread(), "Should be VM thread"); assert(GCLockerInvokesConcurrent || ExplicitGCInvokesConcurrent, "Unexpected"); - GenCollectedHeap* gch = GenCollectedHeap::heap(); - if (_gc_count_before == gch->total_collections()) { + CMSHeap* heap = CMSHeap::heap(); + if (_gc_count_before == heap->total_collections()) { // The "full" of do_full_collection call below "forces" // a collection; the second arg, 0, below ensures that // only the young gen is collected. XXX In the future, @@ -173,21 +174,21 @@ void VM_GenCollectFullConcurrent::doit() { // for the future. assert(SafepointSynchronize::is_at_safepoint(), "We can only be executing this arm of if at a safepoint"); - GCCauseSetter gccs(gch, _gc_cause); - gch->do_full_collection(gch->must_clear_all_soft_refs(), GenCollectedHeap::YoungGen); + GCCauseSetter gccs(heap, _gc_cause); + heap->do_full_collection(heap->must_clear_all_soft_refs(), GenCollectedHeap::YoungGen); } // Else no need for a foreground young gc - assert((_gc_count_before < gch->total_collections()) || + assert((_gc_count_before < heap->total_collections()) || (GCLocker::is_active() /* gc may have been skipped */ - && (_gc_count_before == gch->total_collections())), + && (_gc_count_before == heap->total_collections())), "total_collections() should be monotonically increasing"); MutexLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag); - assert(_full_gc_count_before <= gch->total_full_collections(), "Error"); - if (gch->total_full_collections() == _full_gc_count_before) { + assert(_full_gc_count_before <= heap->total_full_collections(), "Error"); + if (heap->total_full_collections() == _full_gc_count_before) { // Nudge the CMS thread to start a concurrent collection. CMSCollector::request_full_gc(_full_gc_count_before, _gc_cause); } else { - assert(_full_gc_count_before < gch->total_full_collections(), "Error"); + assert(_full_gc_count_before < heap->total_full_collections(), "Error"); FullGCCount_lock->notify_all(); // Inform the Java thread its work is done } } @@ -197,11 +198,11 @@ bool VM_GenCollectFullConcurrent::evaluate_at_safepoint() const { assert(thr != NULL, "Unexpected tid"); if (!thr->is_Java_thread()) { assert(thr->is_VM_thread(), "Expected to be evaluated by VM thread"); - GenCollectedHeap* gch = GenCollectedHeap::heap(); - if (_gc_count_before != gch->total_collections()) { + CMSHeap* heap = CMSHeap::heap(); + if (_gc_count_before != heap->total_collections()) { // No need to do a young gc, we'll just nudge the CMS thread // in the doit() method above, to be executed soon. - assert(_gc_count_before < gch->total_collections(), + assert(_gc_count_before < heap->total_collections(), "total_collections() should be monotonically increasing"); return false; // no need for foreground young gc } @@ -227,9 +228,9 @@ void VM_GenCollectFullConcurrent::doit_epilogue() { // count overflows and wraps around. XXX fix me !!! // e.g. at the rate of 1 full gc per ms, this could // overflow in about 1000 years. - GenCollectedHeap* gch = GenCollectedHeap::heap(); + CMSHeap* heap = CMSHeap::heap(); if (_gc_cause != GCCause::_gc_locker && - gch->total_full_collections_completed() <= _full_gc_count_before) { + heap->total_full_collections_completed() <= _full_gc_count_before) { // maybe we should change the condition to test _gc_cause == // GCCause::_java_lang_system_gc or GCCause::_dcmd_gc_run, // instead of _gc_cause != GCCause::_gc_locker @@ -245,7 +246,7 @@ void VM_GenCollectFullConcurrent::doit_epilogue() { MutexLockerEx ml(FullGCCount_lock, Mutex::_no_safepoint_check_flag); // Either a concurrent or a stop-world full gc is sufficient // witness to our request. - while (gch->total_full_collections_completed() <= _full_gc_count_before) { + while (heap->total_full_collections_completed() <= _full_gc_count_before) { FullGCCount_lock->wait(Mutex::_no_safepoint_check_flag); } } diff --git a/src/hotspot/share/gc/g1/concurrentG1RefineThread.cpp b/src/hotspot/share/gc/g1/concurrentG1RefineThread.cpp index 93903159139..8af13dc078d 100644 --- a/src/hotspot/share/gc/g1/concurrentG1RefineThread.cpp +++ b/src/hotspot/share/gc/g1/concurrentG1RefineThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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 @@ -27,7 +27,7 @@ #include "gc/g1/concurrentG1RefineThread.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1RemSet.hpp" -#include "gc/g1/suspendibleThreadSet.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "runtime/handles.inline.hpp" diff --git a/src/hotspot/share/gc/g1/concurrentMarkThread.cpp b/src/hotspot/share/gc/g1/concurrentMarkThread.cpp index d6930853fd4..feb287a0135 100644 --- a/src/hotspot/share/gc/g1/concurrentMarkThread.cpp +++ b/src/hotspot/share/gc/g1/concurrentMarkThread.cpp @@ -30,12 +30,12 @@ #include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1MMUTracker.hpp" #include "gc/g1/g1Policy.hpp" -#include "gc/g1/suspendibleThreadSet.hpp" #include "gc/g1/vm_operations_g1.hpp" #include "gc/shared/concurrentGCPhaseManager.hpp" #include "gc/shared/gcId.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcTraceTime.inline.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "runtime/vmThread.hpp" @@ -95,7 +95,7 @@ public: _cm(cm) {} void do_void(){ - _cm->checkpointRootsFinal(false); // !clear_all_soft_refs + _cm->checkpoint_roots_final(false); // !clear_all_soft_refs } }; @@ -429,7 +429,7 @@ void ConcurrentMarkThread::run_service() { G1ConcPhase p(G1ConcurrentPhase::CLEANUP_FOR_NEXT_MARK, this); _cm->cleanup_for_next_mark(); } else { - assert(!G1VerifyBitmaps || _cm->nextMarkBitmapIsClear(), "Next mark bitmap must be clear"); + assert(!G1VerifyBitmaps || _cm->next_mark_bitmap_is_clear(), "Next mark bitmap must be clear"); } } diff --git a/src/hotspot/share/gc/g1/dirtyCardQueue.cpp b/src/hotspot/share/gc/g1/dirtyCardQueue.cpp index 9b134474e6f..11c2da764e4 100644 --- a/src/hotspot/share/gc/g1/dirtyCardQueue.cpp +++ b/src/hotspot/share/gc/g1/dirtyCardQueue.cpp @@ -280,13 +280,13 @@ void DirtyCardQueueSet::par_apply_closure_to_all_completed_buffers(CardTableEntr BufferNode* nd = _cur_par_buffer_node; while (nd != NULL) { BufferNode* next = nd->next(); - void* actual = Atomic::cmpxchg_ptr(next, &_cur_par_buffer_node, nd); + BufferNode* actual = Atomic::cmpxchg(next, &_cur_par_buffer_node, nd); if (actual == nd) { bool b = apply_closure_to_buffer(cl, nd, false); guarantee(b, "Should not stop early."); nd = next; } else { - nd = static_cast(actual); + nd = actual; } } } diff --git a/src/hotspot/share/gc/g1/g1CardLiveData.cpp b/src/hotspot/share/gc/g1/g1CardLiveData.cpp index 040bf8b6ca5..0357a84c47c 100644 --- a/src/hotspot/share/gc/g1/g1CardLiveData.cpp +++ b/src/hotspot/share/gc/g1/g1CardLiveData.cpp @@ -26,7 +26,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1CardLiveData.inline.hpp" -#include "gc/g1/suspendibleThreadSet.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/workgroup.hpp" #include "logging/log.hpp" #include "memory/universe.hpp" @@ -313,7 +313,7 @@ public: G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1ConcurrentMark* cm = g1h->concurrent_mark(); - G1CreateLiveDataClosure cl(g1h, cm, cm->nextMarkBitMap(), _live_data); + G1CreateLiveDataClosure cl(g1h, cm, cm->next_mark_bitmap(), _live_data); g1h->heap_region_par_iterate(&cl, worker_id, &_hr_claimer); } }; diff --git a/src/hotspot/share/gc/g1/g1CodeCacheRemSet.cpp b/src/hotspot/share/gc/g1/g1CodeCacheRemSet.cpp index 88611f472ca..bd18ae29621 100644 --- a/src/hotspot/share/gc/g1/g1CodeCacheRemSet.cpp +++ b/src/hotspot/share/gc/g1/g1CodeCacheRemSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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 @@ -155,19 +155,19 @@ G1CodeRootSet::~G1CodeRootSet() { } G1CodeRootSetTable* G1CodeRootSet::load_acquire_table() { - return (G1CodeRootSetTable*) OrderAccess::load_ptr_acquire(&_table); + return OrderAccess::load_acquire(&_table); } void G1CodeRootSet::allocate_small_table() { G1CodeRootSetTable* temp = new G1CodeRootSetTable(SmallSize); - OrderAccess::release_store_ptr(&_table, temp); + OrderAccess::release_store(&_table, temp); } void G1CodeRootSetTable::purge_list_append(G1CodeRootSetTable* table) { for (;;) { table->_purge_next = _purge_list; - G1CodeRootSetTable* old = (G1CodeRootSetTable*) Atomic::cmpxchg_ptr(table, &_purge_list, table->_purge_next); + G1CodeRootSetTable* old = Atomic::cmpxchg(table, &_purge_list, table->_purge_next); if (old == table->_purge_next) { break; } @@ -191,7 +191,7 @@ void G1CodeRootSet::move_to_large() { G1CodeRootSetTable::purge_list_append(_table); - OrderAccess::release_store_ptr(&_table, temp); + OrderAccess::release_store(&_table, temp); } void G1CodeRootSet::purge() { diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 19e2998a50d..006c09fa490 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -57,7 +57,6 @@ #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/heapRegionSet.inline.hpp" -#include "gc/g1/suspendibleThreadSet.hpp" #include "gc/g1/vm_operations_g1.hpp" #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/gcId.hpp" @@ -68,8 +67,10 @@ #include "gc/shared/generationSpec.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "gc/shared/preservedMarks.inline.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/referenceProcessor.inline.hpp" #include "gc/shared/taskqueue.inline.hpp" +#include "gc/shared/weakProcessor.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/iterator.hpp" @@ -141,13 +142,6 @@ void G1RegionMappingChangedListener::on_commit(uint start_idx, size_t num_region reset_from_card_cache(start_idx, num_regions); } -// Returns true if the reference points to an object that -// can move in an incremental collection. -bool G1CollectedHeap::is_scavengable(const void* p) { - HeapRegion* hr = heap_region_containing(p); - return !hr->is_pinned(); -} - // Private methods. HeapRegion* @@ -1774,7 +1768,7 @@ jint G1CollectedHeap::initialize() { vm_shutdown_during_initialization("Could not create/initialize G1ConcurrentMark"); return JNI_ENOMEM; } - _cmThread = _cm->cmThread(); + _cmThread = _cm->cm_thread(); // Now expand into the initial heap size. if (!expand(init_byte_size, _workers)) { @@ -1849,6 +1843,14 @@ void G1CollectedHeap::stop() { } } +void G1CollectedHeap::safepoint_synchronize_begin() { + SuspendibleThreadSet::synchronize(); +} + +void G1CollectedHeap::safepoint_synchronize_end() { + SuspendibleThreadSet::desynchronize(); +} + size_t G1CollectedHeap::conservative_max_heap_alignment() { return HeapRegion::max_region_size(); } @@ -3029,7 +3031,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { g1_policy()->record_collection_pause_start(sample_start_time_sec); if (collector_state()->during_initial_mark_pause()) { - concurrent_mark()->checkpointRootsInitialPre(); + concurrent_mark()->checkpoint_roots_initial_pre(); } g1_policy()->finalize_collection_set(target_pause_time_ms, &_survivor); @@ -3100,7 +3102,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { // We have to do this before we notify the CM threads that // they can start working to make sure that all the // appropriate initialization is done on the CM object. - concurrent_mark()->checkpointRootsInitialPost(); + concurrent_mark()->checkpoint_roots_initial_post(); collector_state()->set_mark_in_progress(true); // Note that we don't actually trigger the CM thread at // this point. We do that later when we're sure that @@ -3458,10 +3460,10 @@ private: // Variables used to claim nmethods. CompiledMethod* _first_nmethod; - volatile CompiledMethod* _claimed_nmethod; + CompiledMethod* volatile _claimed_nmethod; // The list of nmethods that need to be processed by the second pass. - volatile CompiledMethod* _postponed_list; + CompiledMethod* volatile _postponed_list; volatile uint _num_entered_barrier; public: @@ -3480,7 +3482,7 @@ private: if(iter.next_alive()) { _first_nmethod = iter.method(); } - _claimed_nmethod = (volatile CompiledMethod*)_first_nmethod; + _claimed_nmethod = _first_nmethod; } ~G1CodeCacheUnloadingTask() { @@ -3496,9 +3498,9 @@ private: void add_to_postponed_list(CompiledMethod* nm) { CompiledMethod* old; do { - old = (CompiledMethod*)_postponed_list; + old = _postponed_list; nm->set_unloading_next(old); - } while ((CompiledMethod*)Atomic::cmpxchg_ptr(nm, &_postponed_list, old) != old); + } while (Atomic::cmpxchg(nm, &_postponed_list, old) != old); } void clean_nmethod(CompiledMethod* nm) { @@ -3527,7 +3529,7 @@ private: do { *num_claimed_nmethods = 0; - first = (CompiledMethod*)_claimed_nmethod; + first = _claimed_nmethod; last = CompiledMethodIterator(first); if (first != NULL) { @@ -3541,7 +3543,7 @@ private: } } - } while ((CompiledMethod*)Atomic::cmpxchg_ptr(last.method(), &_claimed_nmethod, first) != first); + } while (Atomic::cmpxchg(last.method(), &_claimed_nmethod, first) != first); } CompiledMethod* claim_postponed_nmethod() { @@ -3549,14 +3551,14 @@ private: CompiledMethod* next; do { - claim = (CompiledMethod*)_postponed_list; + claim = _postponed_list; if (claim == NULL) { return NULL; } next = claim->unloading_next(); - } while ((CompiledMethod*)Atomic::cmpxchg_ptr(next, &_postponed_list, claim) != claim); + } while (Atomic::cmpxchg(next, &_postponed_list, claim) != claim); return claim; } @@ -4127,17 +4129,6 @@ public: } }; -void G1CollectedHeap::process_weak_jni_handles() { - double ref_proc_start = os::elapsedTime(); - - G1STWIsAliveClosure is_alive(this); - G1KeepAliveClosure keep_alive(this); - JNIHandles::weak_oops_do(&is_alive, &keep_alive); - - double ref_proc_time = os::elapsedTime() - ref_proc_start; - g1_policy()->phase_times()->record_ref_proc_time(ref_proc_time * 1000.0); -} - void G1CollectedHeap::preserve_cm_referents(G1ParScanThreadStateSet* per_thread_states) { // Any reference objects, in the collection set, that were 'discovered' // by the CM ref processor should have already been copied (either by @@ -4164,7 +4155,7 @@ void G1CollectedHeap::preserve_cm_referents(G1ParScanThreadStateSet* per_thread_ // To avoid spawning task when there is no work to do, check that // a concurrent cycle is active and that some references have been // discovered. - if (concurrent_mark()->cmThread()->during_cycle() && + if (concurrent_mark()->cm_thread()->during_cycle() && ref_processor_cm()->has_discovered_references()) { double preserve_cm_referents_start = os::elapsedTime(); uint no_of_gc_workers = workers()->active_workers(); @@ -4368,14 +4359,23 @@ void G1CollectedHeap::post_evacuate_collection_set(EvacuationInfo& evacuation_in process_discovered_references(per_thread_states); } else { ref_processor_stw()->verify_no_references_recorded(); - process_weak_jni_handles(); + } + + G1STWIsAliveClosure is_alive(this); + G1KeepAliveClosure keep_alive(this); + + { + double start = os::elapsedTime(); + + WeakProcessor::weak_oops_do(&is_alive, &keep_alive); + + double time_ms = (os::elapsedTime() - start) * 1000.0; + g1_policy()->phase_times()->record_ref_proc_time(time_ms); } if (G1StringDedup::is_enabled()) { double fixup_start = os::elapsedTime(); - G1STWIsAliveClosure is_alive(this); - G1KeepAliveClosure keep_alive(this); G1StringDedup::unlink_or_oops_do(&is_alive, &keep_alive, true, g1_policy()->phase_times()); double fixup_time_ms = (os::elapsedTime() - fixup_start) * 1000.0; @@ -4448,7 +4448,7 @@ void G1CollectedHeap::free_region(HeapRegion* hr, if (G1VerifyBitmaps) { MemRegion mr(hr->bottom(), hr->end()); - concurrent_mark()->clearRangePrevBitmap(mr); + concurrent_mark()->clear_range_in_prev_bitmap(mr); } // Clear the card counts for this region. @@ -4814,7 +4814,7 @@ class G1FreeHumongousRegionClosure : public HeapRegionClosure { G1CollectedHeap* g1h = G1CollectedHeap::heap(); oop obj = (oop)r->bottom(); - G1CMBitMap* next_bitmap = g1h->concurrent_mark()->nextMarkBitMap(); + G1CMBitMap* next_bitmap = g1h->concurrent_mark()->next_mark_bitmap(); // The following checks whether the humongous object is live are sufficient. // The main additional check (in addition to having a reference from the roots @@ -5323,17 +5323,20 @@ public: void do_oop(narrowOop* p) { do_oop_work(p); } }; -void G1CollectedHeap::register_nmethod(nmethod* nm) { - CollectedHeap::register_nmethod(nm); +// Returns true if the reference points to an object that +// can move in an incremental collection. +bool G1CollectedHeap::is_scavengable(oop obj) { + HeapRegion* hr = heap_region_containing(obj); + return !hr->is_pinned(); +} +void G1CollectedHeap::register_nmethod(nmethod* nm) { guarantee(nm != NULL, "sanity"); RegisterNMethodOopClosure reg_cl(this, nm); nm->oops_do(®_cl); } void G1CollectedHeap::unregister_nmethod(nmethod* nm) { - CollectedHeap::unregister_nmethod(nm); - guarantee(nm != NULL, "sanity"); UnregisterNMethodOopClosure reg_cl(this, nm); nm->oops_do(®_cl, true); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 5ed6ae89021..fd014af03e8 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -63,7 +63,6 @@ class HRRSCleanupTask; class GenerationSpec; class G1ParScanThreadState; class G1ParScanThreadStateSet; -class G1KlassScanClosure; class G1ParScanThreadState; class ObjectClosure; class SpaceClosure; @@ -304,8 +303,6 @@ private: void trace_heap(GCWhen::Type when, const GCTracer* tracer); - void process_weak_jni_handles(); - // These are macros so that, if the assert fires, we get the correct // line number, file, etc. @@ -969,6 +966,8 @@ public: jint initialize(); virtual void stop(); + virtual void safepoint_synchronize_begin(); + virtual void safepoint_synchronize_end(); // Return the (conservative) maximum heap alignment for any G1 heap static size_t conservative_max_heap_alignment(); @@ -1283,8 +1282,6 @@ public: inline bool is_in_young(const oop obj); - virtual bool is_scavengable(const void* addr); - // We don't need barriers for initializing stores to objects // in the young gen: for the SATB pre-barrier, there is no // pre-value that needs to be remembered; for the remembered-set @@ -1364,7 +1361,7 @@ public: // is not marked, and c) it is not in an archive region. bool is_obj_dead(const oop obj, const HeapRegion* hr) const { return - hr->is_obj_dead(obj, _cm->prevMarkBitMap()) && + hr->is_obj_dead(obj, _cm->prev_mark_bitmap()) && !hr->is_archive(); } @@ -1396,6 +1393,9 @@ public: // Optimized nmethod scanning support routines + // Is an oop scavengeable + virtual bool is_scavengable(oop obj); + // Register the given nmethod with the G1 heap. virtual void register_nmethod(nmethod* nm); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp index 650bb2c032f..982bebfe24a 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp @@ -135,7 +135,7 @@ inline RefToScanQueue* G1CollectedHeap::task_queue(uint i) const { } inline bool G1CollectedHeap::isMarkedNext(oop obj) const { - return _cm->nextMarkBitMap()->is_marked((HeapWord*)obj); + return _cm->next_mark_bitmap()->is_marked((HeapWord*)obj); } inline bool G1CollectedHeap::is_in_cset(oop obj) { diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index aa93d2805fc..d7bb19d0723 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -431,15 +431,15 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) { // Stop adding regions if the remaining reclaimable space is // not above G1HeapWastePercent. size_t reclaimable_bytes = cset_chooser()->remaining_reclaimable_bytes(); - double reclaimable_perc = _policy->reclaimable_bytes_perc(reclaimable_bytes); + double reclaimable_percent = _policy->reclaimable_bytes_percent(reclaimable_bytes); double threshold = (double) G1HeapWastePercent; - if (reclaimable_perc <= threshold) { + if (reclaimable_percent <= threshold) { // We've added enough old regions that the amount of uncollected // reclaimable space is at or below the waste threshold. Stop // adding old regions to the CSet. log_debug(gc, ergo, cset)("Finish adding old regions to CSet (reclaimable percentage not over threshold). " "old %u regions, max %u regions, reclaimable: " SIZE_FORMAT "B (%1.2f%%) threshold: " UINTX_FORMAT "%%", - old_region_length(), max_old_cset_length, reclaimable_bytes, reclaimable_perc, G1HeapWastePercent); + old_region_length(), max_old_cset_length, reclaimable_bytes, reclaimable_percent, G1HeapWastePercent); break; } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 497d07c52b5..bc346a0fbf9 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -38,7 +38,6 @@ #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/heapRegionSet.inline.hpp" -#include "gc/g1/suspendibleThreadSet.hpp" #include "gc/shared/gcId.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" @@ -46,8 +45,10 @@ #include "gc/shared/genOopClosures.inline.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/strongRootsScope.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "gc/shared/vmGCOperations.hpp" +#include "gc/shared/weakProcessor.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/resourceArea.hpp" @@ -325,31 +326,44 @@ bool G1CMRootRegions::wait_until_scan_finished() { return true; } -uint G1ConcurrentMark::scale_parallel_threads(uint n_par_threads) { - return MAX2((n_par_threads + 2) / 4, 1U); +// Returns the maximum number of workers to be used in a concurrent +// phase based on the number of GC workers being used in a STW +// phase. +static uint scale_concurrent_worker_threads(uint num_gc_workers) { + return MAX2((num_gc_workers + 2) / 4, 1U); } -G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev_bitmap_storage, G1RegionToSpaceMapper* next_bitmap_storage) : +G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, + G1RegionToSpaceMapper* prev_bitmap_storage, + G1RegionToSpaceMapper* next_bitmap_storage) : + // _cm_thread set inside the constructor _g1h(g1h), - _markBitMap1(), - _markBitMap2(), - _parallel_marking_threads(0), - _max_parallel_marking_threads(0), - _sleep_factor(0.0), - _marking_task_overhead(1.0), - _cleanup_list("Cleanup List"), + _completed_initialization(false), - _prevMarkBitMap(&_markBitMap1), - _nextMarkBitMap(&_markBitMap2), + _cleanup_list("Concurrent Mark Cleanup List"), + _mark_bitmap_1(), + _mark_bitmap_2(), + _prev_mark_bitmap(&_mark_bitmap_1), + _next_mark_bitmap(&_mark_bitmap_2), + + _heap_start(_g1h->reserved_region().start()), + _heap_end(_g1h->reserved_region().end()), + + _root_regions(), _global_mark_stack(), + // _finger set in set_non_marking_state - _max_worker_id(ParallelGCThreads), - // _active_tasks set in set_non_marking_state + _max_num_tasks(ParallelGCThreads), + // _num_active_tasks set in set_non_marking_state() // _tasks set inside the constructor - _task_queues(new G1CMTaskQueueSet((int) _max_worker_id)), - _terminator(ParallelTaskTerminator((int) _max_worker_id, _task_queues)), + + _task_queues(new G1CMTaskQueueSet((int) _max_num_tasks)), + _terminator(ParallelTaskTerminator((int) _max_num_tasks, _task_queues)), + + _first_overflow_barrier_sync(), + _second_overflow_barrier_sync(), _has_overflown(false), _concurrent(false), @@ -362,87 +376,62 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* // _verbose_level set below _init_times(), - _remark_times(), _remark_mark_times(), _remark_weak_ref_times(), + _remark_times(), + _remark_mark_times(), + _remark_weak_ref_times(), _cleanup_times(), _total_counting_time(0.0), _total_rs_scrub_time(0.0), - _parallel_workers(NULL), + _accum_task_vtime(NULL), - _completed_initialization(false) { + _concurrent_workers(NULL), + _num_concurrent_workers(0), + _max_concurrent_workers(0) +{ + _mark_bitmap_1.initialize(g1h->reserved_region(), prev_bitmap_storage); + _mark_bitmap_2.initialize(g1h->reserved_region(), next_bitmap_storage); - _markBitMap1.initialize(g1h->reserved_region(), prev_bitmap_storage); - _markBitMap2.initialize(g1h->reserved_region(), next_bitmap_storage); - - // Create & start a ConcurrentMark thread. - _cmThread = new ConcurrentMarkThread(this); - assert(cmThread() != NULL, "CM Thread should have been created"); - assert(cmThread()->cm() != NULL, "CM Thread should refer to this cm"); - if (_cmThread->osthread() == NULL) { - vm_shutdown_during_initialization("Could not create ConcurrentMarkThread"); + // Create & start ConcurrentMark thread. + _cm_thread = new ConcurrentMarkThread(this); + if (_cm_thread->osthread() == NULL) { + vm_shutdown_during_initialization("Could not create ConcurrentMarkThread"); } - assert(CGC_lock != NULL, "Where's the CGC_lock?"); + assert(CGC_lock != NULL, "CGC_lock must be initialized"); SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set(); satb_qs.set_buffer_size(G1SATBBufferSize); _root_regions.init(_g1h->survivor(), this); + if (FLAG_IS_DEFAULT(ConcGCThreads) || ConcGCThreads == 0) { + // Calculate the number of concurrent worker threads by scaling + // the number of parallel GC threads. + uint marking_thread_num = scale_concurrent_worker_threads(ParallelGCThreads); + FLAG_SET_ERGO(uint, ConcGCThreads, marking_thread_num); + } + + assert(ConcGCThreads > 0, "ConcGCThreads have been set."); if (ConcGCThreads > ParallelGCThreads) { - log_warning(gc)("Can't have more ConcGCThreads (%u) than ParallelGCThreads (%u).", + log_warning(gc)("More ConcGCThreads (%u) than ParallelGCThreads (%u).", ConcGCThreads, ParallelGCThreads); return; } - if (!FLAG_IS_DEFAULT(ConcGCThreads) && ConcGCThreads > 0) { - // Note: ConcGCThreads has precedence over G1MarkingOverheadPercent - // if both are set - _sleep_factor = 0.0; - _marking_task_overhead = 1.0; - } else if (G1MarkingOverheadPercent > 0) { - // We will calculate the number of parallel marking threads based - // on a target overhead with respect to the soft real-time goal - double marking_overhead = (double) G1MarkingOverheadPercent / 100.0; - double overall_cm_overhead = - (double) MaxGCPauseMillis * marking_overhead / - (double) GCPauseIntervalMillis; - double cpu_ratio = 1.0 / os::initial_active_processor_count(); - double marking_thread_num = ceil(overall_cm_overhead / cpu_ratio); - double marking_task_overhead = - overall_cm_overhead / marking_thread_num * os::initial_active_processor_count(); - double sleep_factor = - (1.0 - marking_task_overhead) / marking_task_overhead; - FLAG_SET_ERGO(uint, ConcGCThreads, (uint) marking_thread_num); - _sleep_factor = sleep_factor; - _marking_task_overhead = marking_task_overhead; - } else { - // Calculate the number of parallel marking threads by scaling - // the number of parallel GC threads. - uint marking_thread_num = scale_parallel_threads(ParallelGCThreads); - FLAG_SET_ERGO(uint, ConcGCThreads, marking_thread_num); - _sleep_factor = 0.0; - _marking_task_overhead = 1.0; - } - - assert(ConcGCThreads > 0, "Should have been set"); log_debug(gc)("ConcGCThreads: %u", ConcGCThreads); log_debug(gc)("ParallelGCThreads: %u", ParallelGCThreads); - _parallel_marking_threads = ConcGCThreads; - _max_parallel_marking_threads = _parallel_marking_threads; - _parallel_workers = new WorkGang("G1 Marker", - _max_parallel_marking_threads, false, true); - if (_parallel_workers == NULL) { - vm_exit_during_initialization("Failed necessary allocation."); - } else { - _parallel_workers->initialize_workers(); - } + _num_concurrent_workers = ConcGCThreads; + _max_concurrent_workers = _num_concurrent_workers; + + _concurrent_workers = new WorkGang("G1 Conc", _max_concurrent_workers, false, true); + _concurrent_workers->initialize_workers(); if (FLAG_IS_DEFAULT(MarkStackSize)) { size_t mark_stack_size = MIN2(MarkStackSizeMax, - MAX2(MarkStackSize, (size_t) (parallel_marking_threads() * TASKQUEUE_SIZE))); + MAX2(MarkStackSize, (size_t) (_max_concurrent_workers * TASKQUEUE_SIZE))); // Verify that the calculated value for MarkStackSize is in range. // It would be nice to use the private utility routine from Arguments. if (!(mark_stack_size >= 1 && mark_stack_size <= MarkStackSizeMax)) { @@ -477,24 +466,22 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* vm_exit_during_initialization("Failed to allocate initial concurrent mark overflow mark stack."); } - _tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_worker_id, mtGC); - _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_worker_id, mtGC); + _tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_num_tasks, mtGC); + _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_num_tasks, mtGC); // so that the assertion in MarkingTaskQueue::task_queue doesn't fail - _active_tasks = _max_worker_id; + _num_active_tasks = _max_num_tasks; - for (uint i = 0; i < _max_worker_id; ++i) { + for (uint i = 0; i < _max_num_tasks; ++i) { G1CMTaskQueue* task_queue = new G1CMTaskQueue(); task_queue->initialize(); _task_queues->register_queue(i, task_queue); - _tasks[i] = new G1CMTask(i, this, task_queue, _task_queues); + _tasks[i] = new G1CMTask(i, this, task_queue); _accum_task_vtime[i] = 0.0; } - // so that the call below can read a sensible value - _heap_start = g1h->reserved_region().start(); set_non_marking_state(); _completed_initialization = true; } @@ -514,11 +501,11 @@ void G1ConcurrentMark::reset() { // Reset all the marking data structures and any necessary flags reset_marking_state(); - // We do reset all of them, since different phases will use + // We reset all of them, since different phases will use // different number of active threads. So, it's easiest to have all // of them ready. - for (uint i = 0; i < _max_worker_id; ++i) { - _tasks[i]->reset(_nextMarkBitMap); + for (uint i = 0; i < _max_num_tasks; ++i) { + _tasks[i]->reset(_next_mark_bitmap); } // we need this to make sure that the flag is on during the evac @@ -538,16 +525,16 @@ void G1ConcurrentMark::reset_marking_state() { clear_has_overflown(); _finger = _heap_start; - for (uint i = 0; i < _max_worker_id; ++i) { + for (uint i = 0; i < _max_num_tasks; ++i) { G1CMTaskQueue* queue = _task_queues->queue(i); queue->set_empty(); } } void G1ConcurrentMark::set_concurrency(uint active_tasks) { - assert(active_tasks <= _max_worker_id, "we should not have more"); + assert(active_tasks <= _max_num_tasks, "we should not have more"); - _active_tasks = active_tasks; + _num_active_tasks = active_tasks; // Need to update the three data structures below according to the // number of active threads for this phase. _terminator = ParallelTaskTerminator((int) active_tasks, _task_queues); @@ -560,8 +547,9 @@ void G1ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurr _concurrent = concurrent; // We propagate this to all tasks, not just the active ones. - for (uint i = 0; i < _max_worker_id; ++i) + for (uint i = 0; i < _max_num_tasks; ++i) { _tasks[i]->set_concurrent(concurrent); + } if (concurrent) { set_concurrent_marking_in_progress(); @@ -580,7 +568,7 @@ void G1ConcurrentMark::set_non_marking_state() { // We set the global marking state to some default values when we're // not doing marking. reset_marking_state(); - _active_tasks = 0; + _num_active_tasks = 0; clear_concurrent_marking_in_progress(); } @@ -623,7 +611,7 @@ private: // as asserts here to minimize their overhead on the product. However, we // will have them as guarantees at the beginning / end of the bitmap // clearing to get some checking in the product. - assert(_cm == NULL || _cm->cmThread()->during_cycle(), "invariant"); + assert(_cm == NULL || _cm->cm_thread()->during_cycle(), "invariant"); assert(_cm == NULL || !G1CollectedHeap::heap()->collector_state()->mark_in_progress(), "invariant"); } assert(cur == end, "Must have completed iteration over the bitmap for region %u.", r->hrm_index()); @@ -672,7 +660,7 @@ void G1ConcurrentMark::clear_bitmap(G1CMBitMap* bitmap, WorkGang* workers, bool void G1ConcurrentMark::cleanup_for_next_mark() { // Make sure that the concurrent mark thread looks to still be in // the current cycle. - guarantee(cmThread()->during_cycle(), "invariant"); + guarantee(cm_thread()->during_cycle(), "invariant"); // We are finishing up the current cycle by clearing the next // marking bitmap and getting it ready for the next cycle. During @@ -680,23 +668,23 @@ void G1ConcurrentMark::cleanup_for_next_mark() { // is the case. guarantee(!_g1h->collector_state()->mark_in_progress(), "invariant"); - clear_bitmap(_nextMarkBitMap, _parallel_workers, true); + clear_bitmap(_next_mark_bitmap, _concurrent_workers, true); // Clear the live count data. If the marking has been aborted, the abort() // call already did that. if (!has_aborted()) { - clear_live_data(_parallel_workers); + clear_live_data(_concurrent_workers); DEBUG_ONLY(verify_live_data_clear()); } // Repeat the asserts from above. - guarantee(cmThread()->during_cycle(), "invariant"); + guarantee(cm_thread()->during_cycle(), "invariant"); guarantee(!_g1h->collector_state()->mark_in_progress(), "invariant"); } void G1ConcurrentMark::clear_prev_bitmap(WorkGang* workers) { assert(SafepointSynchronize::is_at_safepoint(), "Should only clear the entire prev bitmap at a safepoint."); - clear_bitmap(_prevMarkBitMap, workers, false); + clear_bitmap(_prev_mark_bitmap, workers, false); } class CheckBitmapClearHRClosure : public HeapRegionClosure { @@ -716,8 +704,8 @@ class CheckBitmapClearHRClosure : public HeapRegionClosure { } }; -bool G1ConcurrentMark::nextMarkBitmapIsClear() { - CheckBitmapClearHRClosure cl(_nextMarkBitMap); +bool G1ConcurrentMark::next_mark_bitmap_is_clear() { + CheckBitmapClearHRClosure cl(_next_mark_bitmap); _g1h->heap_region_iterate(&cl); return cl.complete(); } @@ -730,7 +718,7 @@ public: } }; -void G1ConcurrentMark::checkpointRootsInitialPre() { +void G1ConcurrentMark::checkpoint_roots_initial_pre() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); _has_aborted = false; @@ -744,7 +732,7 @@ void G1ConcurrentMark::checkpointRootsInitialPre() { } -void G1ConcurrentMark::checkpointRootsInitialPost() { +void G1ConcurrentMark::checkpoint_roots_initial_post() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); // Start Concurrent Marking weak-reference discovery. @@ -842,8 +830,7 @@ private: public: void work(uint worker_id) { - assert(Thread::current()->is_ConcurrentGC_thread(), - "this should only be done by a conc GC thread"); + assert(Thread::current()->is_ConcurrentGC_thread(), "Not a concurrent GC thread"); ResourceMark rm; double start_vtime = os::elapsedVTime(); @@ -852,34 +839,20 @@ public: SuspendibleThreadSetJoiner sts_join; assert(worker_id < _cm->active_tasks(), "invariant"); - G1CMTask* the_task = _cm->task(worker_id); - the_task->record_start_time(); + + G1CMTask* task = _cm->task(worker_id); + task->record_start_time(); if (!_cm->has_aborted()) { do { - double start_vtime_sec = os::elapsedVTime(); - double mark_step_duration_ms = G1ConcMarkStepDurationMillis; + task->do_marking_step(G1ConcMarkStepDurationMillis, + true /* do_termination */, + false /* is_serial*/); - the_task->do_marking_step(mark_step_duration_ms, - true /* do_termination */, - false /* is_serial*/); - - double end_vtime_sec = os::elapsedVTime(); - double elapsed_vtime_sec = end_vtime_sec - start_vtime_sec; _cm->do_yield_check(); - - jlong sleep_time_ms; - if (!_cm->has_aborted() && the_task->has_aborted()) { - sleep_time_ms = - (jlong) (elapsed_vtime_sec * _cm->sleep_factor() * 1000.0); - { - SuspendibleThreadSetLeaver sts_leave; - os::sleep(Thread::current(), sleep_time_ms, false); - } - } - } while (!_cm->has_aborted() && the_task->has_aborted()); + } while (!_cm->has_aborted() && task->has_aborted()); } - the_task->record_end_time(); - guarantee(!the_task->has_aborted() || _cm->has_aborted(), "invariant"); + task->record_end_time(); + guarantee(!task->has_aborted() || _cm->has_aborted(), "invariant"); } double end_vtime = os::elapsedVTime(); @@ -893,30 +866,28 @@ public: ~G1CMConcurrentMarkingTask() { } }; -// Calculates the number of active workers for a concurrent -// phase. -uint G1ConcurrentMark::calc_parallel_marking_threads() { - uint n_conc_workers = 0; +uint G1ConcurrentMark::calc_active_marking_workers() { + uint result = 0; if (!UseDynamicNumberOfGCThreads || (!FLAG_IS_DEFAULT(ConcGCThreads) && !ForceDynamicNumberOfGCThreads)) { - n_conc_workers = max_parallel_marking_threads(); + result = _max_concurrent_workers; } else { - n_conc_workers = - AdaptiveSizePolicy::calc_default_active_workers(max_parallel_marking_threads(), + result = + AdaptiveSizePolicy::calc_default_active_workers(_max_concurrent_workers, 1, /* Minimum workers */ - parallel_marking_threads(), + _num_concurrent_workers, Threads::number_of_non_daemon_threads()); - // Don't scale down "n_conc_workers" by scale_parallel_threads() because - // that scaling has already gone into "_max_parallel_marking_threads". + // Don't scale the result down by scale_concurrent_workers() because + // that scaling has already gone into "_max_concurrent_workers". } - assert(n_conc_workers > 0 && n_conc_workers <= max_parallel_marking_threads(), - "Calculated number of workers must be larger than zero and at most the maximum %u, but is %u", - max_parallel_marking_threads(), n_conc_workers); - return n_conc_workers; + assert(result > 0 && result <= _max_concurrent_workers, + "Calculated number of marking workers must be larger than zero and at most the maximum %u, but is %u", + _max_concurrent_workers, result); + return result; } -void G1ConcurrentMark::scanRootRegion(HeapRegion* hr) { +void G1ConcurrentMark::scan_root_region(HeapRegion* hr) { // Currently, only survivors can be root regions. assert(hr->next_top_at_mark_start() == hr->bottom(), "invariant"); G1RootRegionScanClosure cl(_g1h, this); @@ -948,7 +919,7 @@ public: G1CMRootRegions* root_regions = _cm->root_regions(); HeapRegion* hr = root_regions->claim_next(); while (hr != NULL) { - _cm->scanRootRegion(hr); + _cm->scan_root_region(hr); hr = root_regions->claim_next(); } } @@ -961,17 +932,17 @@ void G1ConcurrentMark::scan_root_regions() { if (root_regions()->scan_in_progress()) { assert(!has_aborted(), "Aborting before root region scanning is finished not supported."); - _parallel_marking_threads = MIN2(calc_parallel_marking_threads(), - // We distribute work on a per-region basis, so starting - // more threads than that is useless. - root_regions()->num_root_regions()); - assert(parallel_marking_threads() <= max_parallel_marking_threads(), + _num_concurrent_workers = MIN2(calc_active_marking_workers(), + // We distribute work on a per-region basis, so starting + // more threads than that is useless. + root_regions()->num_root_regions()); + assert(_num_concurrent_workers <= _max_concurrent_workers, "Maximum number of marking threads exceeded"); G1CMRootRegionScanTask task(this); log_debug(gc, ergo)("Running %s using %u workers for %u work units.", - task.name(), _parallel_marking_threads, root_regions()->num_root_regions()); - _parallel_workers->run_task(&task, _parallel_marking_threads); + task.name(), _num_concurrent_workers, root_regions()->num_root_regions()); + _concurrent_workers->run_task(&task, _num_concurrent_workers); // It's possible that has_aborted() is true here without actually // aborting the survivor scan earlier. This is OK as it's @@ -1010,29 +981,25 @@ void G1ConcurrentMark::mark_from_roots() { _restart_for_overflow = false; - // _g1h has _n_par_threads - _parallel_marking_threads = calc_parallel_marking_threads(); - assert(parallel_marking_threads() <= max_parallel_marking_threads(), - "Maximum number of marking threads exceeded"); + _num_concurrent_workers = calc_active_marking_workers(); - uint active_workers = MAX2(1U, parallel_marking_threads()); - assert(active_workers > 0, "Should have been set"); + uint active_workers = MAX2(1U, _num_concurrent_workers); // Setting active workers is not guaranteed since fewer // worker threads may currently exist and more may not be // available. - active_workers = _parallel_workers->update_active_workers(active_workers); - log_info(gc, task)("Using %u workers of %u for marking", active_workers, _parallel_workers->total_workers()); + active_workers = _concurrent_workers->update_active_workers(active_workers); + log_info(gc, task)("Using %u workers of %u for marking", active_workers, _concurrent_workers->total_workers()); // Parallel task terminator is set in "set_concurrency_and_phase()" set_concurrency_and_phase(active_workers, true /* concurrent */); - G1CMConcurrentMarkingTask markingTask(this, cmThread()); - _parallel_workers->run_task(&markingTask); + G1CMConcurrentMarkingTask marking_task(this, cm_thread()); + _concurrent_workers->run_task(&marking_task); print_stats(); } -void G1ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { +void G1ConcurrentMark::checkpoint_roots_final(bool clear_all_soft_refs) { // world is stopped at this checkpoint assert(SafepointSynchronize::is_at_safepoint(), "world should be stopped"); @@ -1059,11 +1026,11 @@ void G1ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { double start = os::elapsedTime(); - checkpointRootsFinalWork(); + checkpoint_roots_final_work(); double mark_work_end = os::elapsedTime(); - weakRefsWork(clear_all_soft_refs); + weak_refs_work(clear_all_soft_refs); if (has_overflown()) { // We overflowed. Restart concurrent marking. @@ -1257,7 +1224,7 @@ void G1ConcurrentMark::cleanup() { } // Install newly created mark bitMap as "prev". - swapMarkBitMaps(); + swap_mark_bitmaps(); g1h->reset_gc_time_stamp(); @@ -1584,7 +1551,7 @@ void G1CMRefProcTaskExecutor::execute(EnqueueTask& enq_task) { _workers->run_task(&enq_task_proxy); } -void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { +void G1ConcurrentMark::weak_refs_work(bool clear_all_soft_refs) { if (has_overflown()) { // Skip processing the discovered references if we have // overflown the global marking stack. Reference objects @@ -1640,7 +1607,7 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { // we utilize all the worker threads we can. bool processing_is_mt = rp->processing_is_mt(); uint active_workers = (processing_is_mt ? g1h->workers()->active_workers() : 1U); - active_workers = MAX2(MIN2(active_workers, _max_worker_id), 1U); + active_workers = MAX2(MIN2(active_workers, _max_num_tasks), 1U); // Parallel processing task executor. G1CMRefProcTaskExecutor par_task_executor(g1h, this, @@ -1687,6 +1654,14 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { assert(!rp->discovery_enabled(), "Post condition"); } + assert(has_overflown() || _global_mark_stack.is_empty(), + "Mark stack should be empty (unless it has overflown)"); + + { + GCTraceTime(Debug, gc, phases) debug("Weak Processing", _gc_timer_cm); + WeakProcessor::weak_oops_do(&g1_is_alive, &do_nothing_cl); + } + if (has_overflown()) { // We can not trust g1_is_alive if the marking stack overflowed return; @@ -1708,10 +1683,10 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { } } -void G1ConcurrentMark::swapMarkBitMaps() { - G1CMBitMap* temp = _prevMarkBitMap; - _prevMarkBitMap = _nextMarkBitMap; - _nextMarkBitMap = temp; +void G1ConcurrentMark::swap_mark_bitmaps() { + G1CMBitMap* temp = _prev_mark_bitmap; + _prev_mark_bitmap = _next_mark_bitmap; + _next_mark_bitmap = temp; } // Closure for marking entries in SATB buffers. @@ -1811,7 +1786,7 @@ public: } }; -void G1ConcurrentMark::checkpointRootsFinalWork() { +void G1ConcurrentMark::checkpoint_roots_final_work() { ResourceMark rm; HandleMark hm; G1CollectedHeap* g1h = G1CollectedHeap::heap(); @@ -1848,8 +1823,8 @@ void G1ConcurrentMark::checkpointRootsFinalWork() { print_stats(); } -void G1ConcurrentMark::clearRangePrevBitmap(MemRegion mr) { - _prevMarkBitMap->clear_range(mr); +void G1ConcurrentMark::clear_range_in_prev_bitmap(MemRegion mr) { + _prev_mark_bitmap->clear_range(mr); } HeapRegion* @@ -1870,7 +1845,7 @@ G1ConcurrentMark::claim_region(uint worker_id) { HeapWord* end = curr_region != NULL ? curr_region->end() : finger + HeapRegion::GrainWords; // Is the gap between reading the finger and doing the CAS too long? - HeapWord* res = (HeapWord*) Atomic::cmpxchg_ptr(end, &_finger, finger); + HeapWord* res = Atomic::cmpxchg(end, &_finger, finger); if (res == finger && curr_region != NULL) { // we succeeded HeapWord* bottom = curr_region->bottom(); @@ -1937,7 +1912,7 @@ void G1ConcurrentMark::verify_no_cset_oops() { _global_mark_stack.iterate(VerifyNoCSetOops("Stack")); // Verify entries on the task queues - for (uint i = 0; i < _max_worker_id; ++i) { + for (uint i = 0; i < _max_num_tasks; ++i) { G1CMTaskQueue* queue = _task_queues->queue(i); queue->iterate(VerifyNoCSetOops("Queue", i)); } @@ -1954,8 +1929,8 @@ void G1ConcurrentMark::verify_no_cset_oops() { } // Verify the task fingers - assert(parallel_marking_threads() <= _max_worker_id, "sanity"); - for (uint i = 0; i < parallel_marking_threads(); ++i) { + assert(_num_concurrent_workers <= _max_num_tasks, "sanity"); + for (uint i = 0; i < _num_concurrent_workers; ++i) { G1CMTask* task = _tasks[i]; HeapWord* task_finger = task->finger(); if (task_finger != NULL && task_finger < _heap_end) { @@ -1970,15 +1945,15 @@ void G1ConcurrentMark::verify_no_cset_oops() { } #endif // PRODUCT void G1ConcurrentMark::create_live_data() { - _g1h->g1_rem_set()->create_card_live_data(_parallel_workers, _nextMarkBitMap); + _g1h->g1_rem_set()->create_card_live_data(_concurrent_workers, _next_mark_bitmap); } void G1ConcurrentMark::finalize_live_data() { - _g1h->g1_rem_set()->finalize_card_live_data(_g1h->workers(), _nextMarkBitMap); + _g1h->g1_rem_set()->finalize_card_live_data(_g1h->workers(), _next_mark_bitmap); } void G1ConcurrentMark::verify_live_data() { - _g1h->g1_rem_set()->verify_card_live_data(_g1h->workers(), _nextMarkBitMap); + _g1h->g1_rem_set()->verify_card_live_data(_g1h->workers(), _next_mark_bitmap); } void G1ConcurrentMark::clear_live_data(WorkGang* workers) { @@ -1996,14 +1971,14 @@ void G1ConcurrentMark::print_stats() { return; } log_debug(gc, stats)("---------------------------------------------------------------------"); - for (size_t i = 0; i < _active_tasks; ++i) { + for (size_t i = 0; i < _num_active_tasks; ++i) { _tasks[i]->print_stats(); log_debug(gc, stats)("---------------------------------------------------------------------"); } } void G1ConcurrentMark::abort() { - if (!cmThread()->during_cycle() || _has_aborted) { + if (!cm_thread()->during_cycle() || _has_aborted) { // We haven't started a concurrent cycle or we have already aborted it. No need to do anything. return; } @@ -2012,7 +1987,7 @@ void G1ConcurrentMark::abort() { // concurrent bitmap clearing. { GCTraceTime(Debug, gc)("Clear Next Bitmap"); - clear_bitmap(_nextMarkBitMap, _g1h->workers(), false); + clear_bitmap(_next_mark_bitmap, _g1h->workers(), false); } // Note we cannot clear the previous marking bitmap here // since VerifyDuringGC verifies the objects marked during @@ -2028,7 +2003,7 @@ void G1ConcurrentMark::abort() { }) // Empty mark stack reset_marking_state(); - for (uint i = 0; i < _max_worker_id; ++i) { + for (uint i = 0; i < _max_num_tasks; ++i) { _tasks[i]->clear_region_fields(); } _first_overflow_barrier_sync.abort(); @@ -2078,22 +2053,22 @@ void G1ConcurrentMark::print_summary_info() { log.trace(" Total stop_world time = %8.2f s.", (_init_times.sum() + _remark_times.sum() + _cleanup_times.sum())/1000.0); log.trace(" Total concurrent time = %8.2f s (%8.2f s marking).", - cmThread()->vtime_accum(), cmThread()->vtime_mark_accum()); + cm_thread()->vtime_accum(), cm_thread()->vtime_mark_accum()); } void G1ConcurrentMark::print_worker_threads_on(outputStream* st) const { - _parallel_workers->print_worker_threads_on(st); + _concurrent_workers->print_worker_threads_on(st); } void G1ConcurrentMark::threads_do(ThreadClosure* tc) const { - _parallel_workers->threads_do(tc); + _concurrent_workers->threads_do(tc); } void G1ConcurrentMark::print_on_error(outputStream* st) const { st->print_cr("Marking Bits (Prev, Next): (CMBitMap*) " PTR_FORMAT ", (CMBitMap*) " PTR_FORMAT, - p2i(_prevMarkBitMap), p2i(_nextMarkBitMap)); - _prevMarkBitMap->print_on_error(st, " Prev Bits: "); - _nextMarkBitMap->print_on_error(st, " Next Bits: "); + p2i(_prev_mark_bitmap), p2i(_next_mark_bitmap)); + _prev_mark_bitmap->print_on_error(st, " Prev Bits: "); + _next_mark_bitmap->print_on_error(st, " Next Bits: "); } static ReferenceProcessor* get_cm_oop_closure_ref_processor(G1CollectedHeap* g1h) { @@ -2171,9 +2146,9 @@ void G1CMTask::set_cm_oop_closure(G1CMOopClosure* cm_oop_closure) { _cm_oop_closure = cm_oop_closure; } -void G1CMTask::reset(G1CMBitMap* nextMarkBitMap) { - guarantee(nextMarkBitMap != NULL, "invariant"); - _nextMarkBitMap = nextMarkBitMap; +void G1CMTask::reset(G1CMBitMap* next_mark_bitmap) { + guarantee(next_mark_bitmap != NULL, "invariant"); + _next_mark_bitmap = next_mark_bitmap; clear_region_fields(); _calls = 0; @@ -2215,7 +2190,9 @@ void G1CMTask::regular_clock_call() { // If we are not concurrent (i.e. we're doing remark) we don't need // to check anything else. The other steps are only needed during // the concurrent marking phase. - if (!concurrent()) return; + if (!_concurrent) { + return; + } // (2) If marking has been aborted for Full GC, then we also abort. if (_cm->has_aborted()) { @@ -2267,10 +2244,8 @@ void G1CMTask::decrease_limits() { // entries to/from the global stack). It basically tries to decrease the // scanning limit so that the clock is called earlier. - _words_scanned_limit = _real_words_scanned_limit - - 3 * words_scanned_period / 4; - _refs_reached_limit = _real_refs_reached_limit - - 3 * refs_reached_period / 4; + _words_scanned_limit = _real_words_scanned_limit - 3 * words_scanned_period / 4; + _refs_reached_limit = _real_refs_reached_limit - 3 * refs_reached_period / 4; } void G1CMTask::move_entries_to_global_stack() { @@ -2409,7 +2384,7 @@ void G1CMTask::drain_satb_buffers() { _draining_satb_buffers = false; assert(has_aborted() || - concurrent() || + _concurrent || satb_mq_set.completed_buffers_num() == 0, "invariant"); // again, this was a potentially expensive operation, decrease the @@ -2418,7 +2393,7 @@ void G1CMTask::drain_satb_buffers() { } void G1CMTask::print_stats() { - log_debug(gc, stats)("Marking Stats, task = %u, calls = %d", + log_debug(gc, stats)("Marking Stats, task = %u, calls = %u", _worker_id, _calls); log_debug(gc, stats)(" Elapsed time = %1.2lfms, Termination time = %1.2lfms", _elapsed_time_ms, _termination_time_ms); @@ -2552,21 +2527,7 @@ void G1CMTask::do_marking_step(double time_target_ms, bool do_termination, bool is_serial) { assert(time_target_ms >= 1.0, "minimum granularity is 1ms"); - assert(concurrent() == _cm->concurrent(), "they should be the same"); - - G1Policy* g1_policy = _g1h->g1_policy(); - assert(_task_queues != NULL, "invariant"); - assert(_task_queue != NULL, "invariant"); - assert(_task_queues->queue(_worker_id) == _task_queue, "invariant"); - - assert(!_claimed, - "only one thread should claim this task at any one time"); - - // OK, this doesn't safeguard again all possible scenarios, as it is - // possible for two threads to set the _claimed flag at the same - // time. But it is only for debugging purposes anyway and it will - // catch most problems. - _claimed = true; + assert(_concurrent == _cm->concurrent(), "they should be the same"); _start_time_ms = os::elapsedVTime() * 1000.0; @@ -2651,7 +2612,7 @@ void G1CMTask::do_marking_step(double time_target_ms, giveup_current_region(); regular_clock_call(); } else if (_curr_region->is_humongous() && mr.start() == _curr_region->bottom()) { - if (_nextMarkBitMap->is_marked(mr.start())) { + if (_next_mark_bitmap->is_marked(mr.start())) { // The object is marked - apply the closure bitmap_closure.do_addr(mr.start()); } @@ -2659,7 +2620,7 @@ void G1CMTask::do_marking_step(double time_target_ms, // we can (and should) give up the current region. giveup_current_region(); regular_clock_call(); - } else if (_nextMarkBitMap->iterate(&bitmap_closure, mr)) { + } else if (_next_mark_bitmap->iterate(&bitmap_closure, mr)) { giveup_current_region(); regular_clock_call(); } else { @@ -2787,10 +2748,10 @@ void G1CMTask::do_marking_step(double time_target_ms, // We're all done. if (_worker_id == 0) { - // let's allow task 0 to do this - if (concurrent()) { + // Let's allow task 0 to do this + if (_concurrent) { assert(_cm->concurrent_marking_in_progress(), "invariant"); - // we need to set this to false before the next + // We need to set this to false before the next // safepoint. This way we ensure that the marking phase // doesn't observe any more heap expansions. _cm->clear_concurrent_marking_in_progress(); @@ -2862,24 +2823,40 @@ void G1CMTask::do_marking_step(double time_target_ms, // ready to restart. } } - - _claimed = false; } -G1CMTask::G1CMTask(uint worker_id, - G1ConcurrentMark* cm, - G1CMTaskQueue* task_queue, - G1CMTaskQueueSet* task_queues) - : _g1h(G1CollectedHeap::heap()), - _worker_id(worker_id), _cm(cm), - _objArray_processor(this), - _claimed(false), - _nextMarkBitMap(NULL), _hash_seed(17), - _task_queue(task_queue), - _task_queues(task_queues), - _cm_oop_closure(NULL) { +G1CMTask::G1CMTask(uint worker_id, G1ConcurrentMark* cm, G1CMTaskQueue* task_queue) : + _objArray_processor(this), + _worker_id(worker_id), + _g1h(G1CollectedHeap::heap()), + _cm(cm), + _next_mark_bitmap(NULL), + _task_queue(task_queue), + _calls(0), + _time_target_ms(0.0), + _start_time_ms(0.0), + _cm_oop_closure(NULL), + _curr_region(NULL), + _finger(NULL), + _region_limit(NULL), + _words_scanned(0), + _words_scanned_limit(0), + _real_words_scanned_limit(0), + _refs_reached(0), + _refs_reached_limit(0), + _real_refs_reached_limit(0), + _hash_seed(17), + _has_aborted(false), + _has_timed_out(false), + _draining_satb_buffers(false), + _step_times_ms(), + _elapsed_time_ms(0.0), + _termination_time_ms(0.0), + _termination_start_time_ms(0.0), + _concurrent(false), + _marking_step_diffs_ms() +{ guarantee(task_queue != NULL, "invariant"); - guarantee(task_queues != NULL, "invariant"); _marking_step_diffs_ms.add(0.5); } @@ -2916,11 +2893,11 @@ G1CMTask::G1CMTask(uint worker_id, #define G1PPRL_SUM_MB_FORMAT(tag) " " tag ": %1.2f MB" #define G1PPRL_SUM_MB_PERC_FORMAT(tag) G1PPRL_SUM_MB_FORMAT(tag) " / %1.2f %%" -G1PrintRegionLivenessInfoClosure:: -G1PrintRegionLivenessInfoClosure(const char* phase_name) - : _total_used_bytes(0), _total_capacity_bytes(0), - _total_prev_live_bytes(0), _total_next_live_bytes(0), - _total_remset_bytes(0), _total_strong_code_roots_bytes(0) { +G1PrintRegionLivenessInfoClosure::G1PrintRegionLivenessInfoClosure(const char* phase_name) : + _total_used_bytes(0), _total_capacity_bytes(0), + _total_prev_live_bytes(0), _total_next_live_bytes(0), + _total_remset_bytes(0), _total_strong_code_roots_bytes(0) +{ G1CollectedHeap* g1h = G1CollectedHeap::heap(); MemRegion g1_reserved = g1h->g1_reserved(); double now = os::elapsedTime(); @@ -3010,11 +2987,11 @@ G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() { G1PPRL_SUM_MB_FORMAT("code-roots"), bytes_to_mb(_total_capacity_bytes), bytes_to_mb(_total_used_bytes), - perc(_total_used_bytes, _total_capacity_bytes), + percent_of(_total_used_bytes, _total_capacity_bytes), bytes_to_mb(_total_prev_live_bytes), - perc(_total_prev_live_bytes, _total_capacity_bytes), + percent_of(_total_prev_live_bytes, _total_capacity_bytes), bytes_to_mb(_total_next_live_bytes), - perc(_total_next_live_bytes, _total_capacity_bytes), + percent_of(_total_next_live_bytes, _total_capacity_bytes), bytes_to_mb(_total_remset_bytes), bytes_to_mb(_total_strong_code_roots_bytes)); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index d2e2f67f23f..57685cc0cb7 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -25,18 +25,18 @@ #ifndef SHARE_VM_GC_G1_G1CONCURRENTMARK_HPP #define SHARE_VM_GC_G1_G1CONCURRENTMARK_HPP -#include "classfile/javaClasses.hpp" #include "gc/g1/g1ConcurrentMarkBitMap.hpp" #include "gc/g1/g1ConcurrentMarkObjArrayProcessor.hpp" -#include "gc/g1/g1RegionToSpaceMapper.hpp" #include "gc/g1/heapRegionSet.hpp" #include "gc/shared/taskqueue.hpp" +class ConcurrentGCTimer; +class ConcurrentMarkThread; class G1CollectedHeap; class G1CMTask; class G1ConcurrentMark; -class ConcurrentGCTimer; class G1OldTracer; +class G1RegionToSpaceMapper; class G1SurvivorRegions; #ifdef _MSC_VER @@ -272,12 +272,10 @@ public: bool wait_until_scan_finished(); }; -class ConcurrentMarkThread; - +// This class manages data structures and methods for doing liveness analysis in +// G1's concurrent cycle. class G1ConcurrentMark: public CHeapObj { friend class ConcurrentMarkThread; - friend class G1ParNoteEndTask; - friend class G1VerifyLiveDataClosure; friend class G1CMRefProcTaskProxy; friend class G1CMRefProcTaskExecutor; friend class G1CMKeepAliveAndDrainClosure; @@ -287,46 +285,37 @@ class G1ConcurrentMark: public CHeapObj { friend class G1CMRemarkTask; friend class G1CMTask; -protected: - ConcurrentMarkThread* _cmThread; // The thread doing the work - G1CollectedHeap* _g1h; // The heap - uint _parallel_marking_threads; // The number of marking - // threads we're using - uint _max_parallel_marking_threads; // Max number of marking - // threads we'll ever use - double _sleep_factor; // How much we have to sleep, with - // respect to the work we just did, to - // meet the marking overhead goal - double _marking_task_overhead; // Marking target overhead for - // a single task + ConcurrentMarkThread* _cm_thread; // The thread doing the work + G1CollectedHeap* _g1h; // The heap + bool _completed_initialization; // Set to true when initialization is complete - FreeRegionList _cleanup_list; + FreeRegionList _cleanup_list; // Concurrent marking support structures - G1CMBitMap _markBitMap1; - G1CMBitMap _markBitMap2; - G1CMBitMap* _prevMarkBitMap; // Completed mark bitmap - G1CMBitMap* _nextMarkBitMap; // Under-construction mark bitmap + G1CMBitMap _mark_bitmap_1; + G1CMBitMap _mark_bitmap_2; + G1CMBitMap* _prev_mark_bitmap; // Completed mark bitmap + G1CMBitMap* _next_mark_bitmap; // Under-construction mark bitmap // Heap bounds - HeapWord* _heap_start; - HeapWord* _heap_end; + HeapWord* _heap_start; + HeapWord* _heap_end; // Root region tracking and claiming - G1CMRootRegions _root_regions; + G1CMRootRegions _root_regions; - // For gray objects - G1CMMarkStack _global_mark_stack; // Grey objects behind global finger - HeapWord* volatile _finger; // The global finger, region aligned, - // always points to the end of the - // last claimed region + // For grey objects + G1CMMarkStack _global_mark_stack; // Grey objects behind global finger + HeapWord* volatile _finger; // The global finger, region aligned, + // always pointing to the end of the + // last claimed region - // Marking tasks - uint _max_worker_id;// Maximum worker id - uint _active_tasks; // Task num currently active - G1CMTask** _tasks; // Task queue array (max_worker_id len) - G1CMTaskQueueSet* _task_queues; // Task queue set - ParallelTaskTerminator _terminator; // For termination + uint _max_num_tasks; // Maximum number of marking tasks + uint _num_active_tasks; // Number of tasks currently active + G1CMTask** _tasks; // Task queue array (max_worker_id length) + + G1CMTaskQueueSet* _task_queues; // Task queue set + ParallelTaskTerminator _terminator; // For termination // Two sync barriers that are used to synchronize tasks when an // overflow occurs. The algorithm is the following. All tasks enter @@ -337,32 +326,32 @@ protected: // ensure, that no task starts doing work before all data // structures (local and global) have been re-initialized. When they // exit it, they are free to start working again. - WorkGangBarrierSync _first_overflow_barrier_sync; - WorkGangBarrierSync _second_overflow_barrier_sync; + WorkGangBarrierSync _first_overflow_barrier_sync; + WorkGangBarrierSync _second_overflow_barrier_sync; // This is set by any task, when an overflow on the global data // structures is detected - volatile bool _has_overflown; + volatile bool _has_overflown; // True: marking is concurrent, false: we're in remark - volatile bool _concurrent; + volatile bool _concurrent; // Set at the end of a Full GC so that marking aborts - volatile bool _has_aborted; + volatile bool _has_aborted; // Used when remark aborts due to an overflow to indicate that // another concurrent marking phase should start - volatile bool _restart_for_overflow; + volatile bool _restart_for_overflow; // This is true from the very start of concurrent marking until the // point when all the tasks complete their work. It is really used // to determine the points between the end of concurrent marking and // time of remark. - volatile bool _concurrent_marking_in_progress; + volatile bool _concurrent_marking_in_progress; - ConcurrentGCTimer* _gc_timer_cm; + ConcurrentGCTimer* _gc_timer_cm; - G1OldTracer* _gc_tracer_cm; + G1OldTracer* _gc_tracer_cm; - // All of these times are in ms + // Timing statistics. All of them are in ms NumberSeq _init_times; NumberSeq _remark_times; NumberSeq _remark_mark_times; @@ -373,14 +362,16 @@ protected: double* _accum_task_vtime; // Accumulated task vtime - WorkGang* _parallel_workers; + WorkGang* _concurrent_workers; + uint _num_concurrent_workers; // The number of marking worker threads we're using + uint _max_concurrent_workers; // Maximum number of marking worker threads - void weakRefsWorkParallelPart(BoolObjectClosure* is_alive, bool purged_classes); - void weakRefsWork(bool clear_all_soft_refs); + void weak_refs_work_parallel_part(BoolObjectClosure* is_alive, bool purged_classes); + void weak_refs_work(bool clear_all_soft_refs); - void swapMarkBitMaps(); + void swap_mark_bitmaps(); - // It resets the global marking data structures, as well as the + // Resets the global marking data structures, as well as the // task local ones; should be called during initial mark. void reset(); @@ -395,7 +386,7 @@ protected: // Called to indicate how many threads are currently active. void set_concurrency(uint active_tasks); - // It should be called to indicate which phase we're in (concurrent + // Should be called to indicate which phase we're in (concurrent // mark or remark) and how many threads are currently active. void set_concurrency_and_phase(uint active_tasks, bool concurrent); @@ -406,18 +397,12 @@ protected: return _cleanup_list.is_empty(); } - // Accessor methods - uint parallel_marking_threads() const { return _parallel_marking_threads; } - uint max_parallel_marking_threads() const { return _max_parallel_marking_threads;} - double sleep_factor() { return _sleep_factor; } - double marking_task_overhead() { return _marking_task_overhead;} - HeapWord* finger() { return _finger; } bool concurrent() { return _concurrent; } - uint active_tasks() { return _active_tasks; } + uint active_tasks() { return _num_active_tasks; } ParallelTaskTerminator* terminator() { return &_terminator; } - // It claims the next available region to be scanned by a marking + // Claims the next available region to be scanned by a marking // task/thread. It might return NULL if the next region is empty or // we have run out of regions. In the latter case, out_of_regions() // determines whether we've really run out of regions or the task @@ -433,30 +418,19 @@ protected: // frequently. HeapRegion* claim_region(uint worker_id); - // It determines whether we've run out of regions to scan. Note that + // Determines whether we've run out of regions to scan. Note that // the finger can point past the heap end in case the heap was expanded // to satisfy an allocation without doing a GC. This is fine, because all // objects in those regions will be considered live anyway because of // SATB guarantees (i.e. their TAMS will be equal to bottom). - bool out_of_regions() { return _finger >= _heap_end; } + bool out_of_regions() { return _finger >= _heap_end; } // Returns the task with the given id - G1CMTask* task(int id) { - assert(0 <= id && id < (int) _active_tasks, - "task id not within active bounds"); + G1CMTask* task(uint id) { + assert(id < _num_active_tasks, "Task id %u not within active bounds up to %u", id, _num_active_tasks); return _tasks[id]; } - // Returns the task queue with the given id - G1CMTaskQueue* task_queue(int id) { - assert(0 <= id && id < (int) _active_tasks, - "task queue id not within active bounds"); - return (G1CMTaskQueue*) _task_queues->queue(id); - } - - // Returns the task queue set - G1CMTaskQueueSet* task_queues() { return _task_queues; } - // Access / manipulation of the overflow flag which is set to // indicate that the global stack has overflown bool has_overflown() { return _has_overflown; } @@ -468,16 +442,6 @@ protected: void enter_first_sync_barrier(uint worker_id); void enter_second_sync_barrier(uint worker_id); - // Card index of the bottom of the G1 heap. Used for biasing indices into - // the card bitmaps. - intptr_t _heap_bottom_card_num; - - // Set to true when initialization is complete - bool _completed_initialization; - - // end_timer, true to end gc timer after ending concurrent phase. - void register_concurrent_phase_end_common(bool end_timer); - // Clear the given bitmap in parallel using the given WorkGang. If may_yield is // true, periodically insert checks to see if this method should exit prematurely. void clear_bitmap(G1CMBitMap* bitmap, WorkGang* workers, bool may_yield); @@ -495,13 +459,13 @@ public: bool mark_stack_pop(G1TaskQueueEntry* arr) { return _global_mark_stack.par_pop_chunk(arr); } - size_t mark_stack_size() { return _global_mark_stack.size(); } - size_t partial_mark_stack_size_target() { return _global_mark_stack.capacity()/3; } - bool mark_stack_empty() { return _global_mark_stack.is_empty(); } + size_t mark_stack_size() const { return _global_mark_stack.size(); } + size_t partial_mark_stack_size_target() const { return _global_mark_stack.capacity() / 3; } + bool mark_stack_empty() const { return _global_mark_stack.is_empty(); } G1CMRootRegions* root_regions() { return &_root_regions; } - bool concurrent_marking_in_progress() { + bool concurrent_marking_in_progress() const { return _concurrent_marking_in_progress; } void set_concurrent_marking_in_progress() { @@ -520,7 +484,7 @@ public: double all_task_accum_vtime() { double ret = 0.0; - for (uint i = 0; i < _max_worker_id; ++i) + for (uint i = 0; i < _max_num_tasks; ++i) ret += _accum_task_vtime[i]; return ret; } @@ -533,18 +497,13 @@ public: G1RegionToSpaceMapper* next_bitmap_storage); ~G1ConcurrentMark(); - ConcurrentMarkThread* cmThread() { return _cmThread; } + ConcurrentMarkThread* cm_thread() { return _cm_thread; } - const G1CMBitMap* const prevMarkBitMap() const { return _prevMarkBitMap; } - G1CMBitMap* nextMarkBitMap() const { return _nextMarkBitMap; } + const G1CMBitMap* const prev_mark_bitmap() const { return _prev_mark_bitmap; } + G1CMBitMap* next_mark_bitmap() const { return _next_mark_bitmap; } - // Returns the number of GC threads to be used in a concurrent - // phase based on the number of GC threads being used in a STW - // phase. - uint scale_parallel_threads(uint n_par_threads); - - // Calculates the number of GC threads to be used in a concurrent phase. - uint calc_parallel_marking_threads(); + // Calculates the number of concurrent GC threads to be used in the marking phase. + uint calc_active_marking_workers(); // Prepare internal data structures for the next mark cycle. This includes clearing // the next mark bitmap and some internal data structures. This method is intended @@ -556,48 +515,49 @@ public: // Return whether the next mark bitmap has no marks set. To be used for assertions // only. Will not yield to pause requests. - bool nextMarkBitmapIsClear(); + bool next_mark_bitmap_is_clear(); // These two do the work that needs to be done before and after the // initial root checkpoint. Since this checkpoint can be done at two // different points (i.e. an explicit pause or piggy-backed on a // young collection), then it's nice to be able to easily share the // pre/post code. It might be the case that we can put everything in - // the post method. TP - void checkpointRootsInitialPre(); - void checkpointRootsInitialPost(); + // the post method. + void checkpoint_roots_initial_pre(); + void checkpoint_roots_initial_post(); // Scan all the root regions and mark everything reachable from // them. void scan_root_regions(); // Scan a single root region and mark everything reachable from it. - void scanRootRegion(HeapRegion* hr); + void scan_root_region(HeapRegion* hr); // Do concurrent phase of marking, to a tentative transitive closure. void mark_from_roots(); - void checkpointRootsFinal(bool clear_all_soft_refs); - void checkpointRootsFinalWork(); + void checkpoint_roots_final(bool clear_all_soft_refs); + void checkpoint_roots_final_work(); + void cleanup(); void complete_cleanup(); - // Mark in the previous bitmap. NB: this is usually read-only, so use - // this carefully! - inline void markPrev(oop p); + // Mark in the previous bitmap. Caution: the prev bitmap is usually read-only, so use + // this carefully. + inline void mark_in_prev_bitmap(oop p); // Clears marks for all objects in the given range, for the prev or - // next bitmaps. NB: the previous bitmap is usually + // next bitmaps. Caution: the previous bitmap is usually // read-only, so use this carefully! - void clearRangePrevBitmap(MemRegion mr); + void clear_range_in_prev_bitmap(MemRegion mr); + + inline bool is_marked_in_prev_bitmap(oop p) const; // Verify that there are no CSet oops on the stacks (taskqueues / // global mark stack) and fingers (global / per-task). // If marking is not in progress, it's a no-op. void verify_no_cset_oops() PRODUCT_RETURN; - inline bool isPrevMarked(oop p) const; - inline bool do_yield_check(); // Abandon current marking iteration due to a Full GC. @@ -661,78 +621,71 @@ private: uint _worker_id; G1CollectedHeap* _g1h; G1ConcurrentMark* _cm; - G1CMBitMap* _nextMarkBitMap; + G1CMBitMap* _next_mark_bitmap; // the task queue of this task G1CMTaskQueue* _task_queue; -private: - // the task queue set---needed for stealing - G1CMTaskQueueSet* _task_queues; - // indicates whether the task has been claimed---this is only for - // debugging purposes - bool _claimed; - // number of calls to this task - int _calls; + // Number of calls to this task + uint _calls; - // when the virtual timer reaches this time, the marking step should - // exit + // When the virtual timer reaches this time, the marking step should exit double _time_target_ms; - // the start time of the current marking step + // Start time of the current marking step double _start_time_ms; - // the oop closure used for iterations over oops + // Oop closure used for iterations over oops G1CMOopClosure* _cm_oop_closure; - // the region this task is scanning, NULL if we're not scanning any + // Region this task is scanning, NULL if we're not scanning any HeapRegion* _curr_region; - // the local finger of this task, NULL if we're not scanning a region + // Local finger of this task, NULL if we're not scanning a region HeapWord* _finger; - // limit of the region this task is scanning, NULL if we're not scanning one + // Limit of the region this task is scanning, NULL if we're not scanning one HeapWord* _region_limit; - // the number of words this task has scanned + // Number of words this task has scanned size_t _words_scanned; // When _words_scanned reaches this limit, the regular clock is // called. Notice that this might be decreased under certain // circumstances (i.e. when we believe that we did an expensive // operation). size_t _words_scanned_limit; - // the initial value of _words_scanned_limit (i.e. what it was + // Initial value of _words_scanned_limit (i.e. what it was // before it was decreased). size_t _real_words_scanned_limit; - // the number of references this task has visited + // Number of references this task has visited size_t _refs_reached; // When _refs_reached reaches this limit, the regular clock is // called. Notice this this might be decreased under certain // circumstances (i.e. when we believe that we did an expensive // operation). size_t _refs_reached_limit; - // the initial value of _refs_reached_limit (i.e. what it was before + // Initial value of _refs_reached_limit (i.e. what it was before // it was decreased). size_t _real_refs_reached_limit; - // used by the work stealing stuff + // Used by the work stealing int _hash_seed; - // if this is true, then the task has aborted for some reason + // If true, then the task has aborted for some reason bool _has_aborted; - // set when the task aborts because it has met its time quota + // Set when the task aborts because it has met its time quota bool _has_timed_out; - // true when we're draining SATB buffers; this avoids the task + // True when we're draining SATB buffers; this avoids the task // aborting due to SATB buffers being available (as we're already // dealing with them) bool _draining_satb_buffers; - // number sequence of past step times + // Number sequence of past step times NumberSeq _step_times_ms; - // elapsed time of this task + // Elapsed time of this task double _elapsed_time_ms; - // termination time of this task + // Termination time of this task double _termination_time_ms; - // when this task got into the termination protocol + // When this task got into the termination protocol double _termination_start_time_ms; - // true when the task is during a concurrent phase, false when it is + // True when the task is during a concurrent phase, false when it is // in the remark phase (so, in the latter case, we do not have to // check all the things that we have to check during the concurrent // phase, i.e. SATB buffer availability...) @@ -740,21 +693,21 @@ private: TruncatedSeq _marking_step_diffs_ms; - // it updates the local fields after this task has claimed + // Updates the local fields after this task has claimed // a new region to scan void setup_for_region(HeapRegion* hr); - // it brings up-to-date the limit of the region + // Makes the limit of the region up-to-date void update_region_limit(); - // called when either the words scanned or the refs visited limit + // Called when either the words scanned or the refs visited limit // has been reached void reached_limit(); - // recalculates the words scanned and refs visited limits + // Recalculates the words scanned and refs visited limits void recalculate_limits(); - // decreases the words scanned and refs visited limits when we reach + // Decreases the words scanned and refs visited limits when we reach // an expensive operation void decrease_limits(); - // it checks whether the words scanned or refs visited reached their + // Checks whether the words scanned or refs visited reached their // respective limit and calls reached_limit() if they have void check_limits() { if (_words_scanned >= _words_scanned_limit || @@ -762,11 +715,10 @@ private: reached_limit(); } } - // this is supposed to be called regularly during a marking step as + // Supposed to be called regularly during a marking step as // it checks a bunch of conditions that might cause the marking step // to abort void regular_clock_call(); - bool concurrent() { return _concurrent; } // Test whether obj might have already been passed over by the // mark bitmap scan, and so needs to be pushed onto the mark stack. @@ -777,10 +729,9 @@ public: // Apply the closure on the given area of the objArray. Return the number of words // scanned. inline size_t scan_objArray(objArrayOop obj, MemRegion mr); - // It resets the task; it should be called right at the beginning of - // a marking phase. - void reset(G1CMBitMap* _nextMarkBitMap); - // it clears all the fields that correspond to a claimed region. + // Resets the task; should be called right at the beginning of a marking phase. + void reset(G1CMBitMap* next_mark_bitmap); + // Clears all the fields that correspond to a claimed region. void clear_region_fields(); void set_concurrent(bool concurrent) { _concurrent = concurrent; } @@ -801,7 +752,7 @@ public: _elapsed_time_ms = os::elapsedTime() * 1000.0 - _elapsed_time_ms; } - // returns the worker ID associated with this task. + // Returns the worker ID associated with this task. uint worker_id() { return _worker_id; } // From TerminatorTerminator. It determines whether this task should @@ -818,8 +769,6 @@ public: bool has_aborted() { return _has_aborted; } void set_has_aborted() { _has_aborted = true; } void clear_has_aborted() { _has_aborted = false; } - bool has_timed_out() { return _has_timed_out; } - bool claimed() { return _claimed; } void set_cm_oop_closure(G1CMOopClosure* cm_oop_closure); @@ -836,10 +785,10 @@ public: // Precondition: obj is a valid heap object. inline void deal_with_reference(oop obj); - // It scans an object and visits its children. + // Scans an object and visits its children. inline void scan_task_entry(G1TaskQueueEntry task_entry); - // It pushes an object on the local queue. + // Pushes an object on the local queue. inline void push(G1TaskQueueEntry task_entry); // Move entries to the global stack. @@ -847,20 +796,20 @@ public: // Move entries from the global stack, return true if we were successful to do so. bool get_entries_from_global_stack(); - // It pops and scans objects from the local queue. If partially is + // Pops and scans objects from the local queue. If partially is // true, then it stops when the queue size is of a given limit. If // partially is false, then it stops when the queue is empty. void drain_local_queue(bool partially); - // It moves entries from the global stack to the local queue and + // Moves entries from the global stack to the local queue and // drains the local queue. If partially is true, then it stops when // both the global stack and the local queue reach a given size. If // partially if false, it tries to empty them totally. void drain_global_stack(bool partially); - // It keeps picking SATB buffers and processing them until no SATB + // Keeps picking SATB buffers and processing them until no SATB // buffers are available. void drain_satb_buffers(); - // moves the local finger to a new location + // Moves the local finger to a new location inline void move_finger_to(HeapWord* new_finger) { assert(new_finger >= _finger && new_finger < _region_limit, "invariant"); _finger = new_finger; @@ -868,10 +817,9 @@ public: G1CMTask(uint worker_id, G1ConcurrentMark *cm, - G1CMTaskQueue* task_queue, - G1CMTaskQueueSet* task_queues); + G1CMTaskQueue* task_queue); - // it prints statistics associated with this task + // Prints statistics associated with this task void print_stats(); }; @@ -892,14 +840,6 @@ private: // Accumulator for strong code roots memory size size_t _total_strong_code_roots_bytes; - static double perc(size_t val, size_t total) { - if (total == 0) { - return 0.0; - } else { - return 100.0 * ((double) val / (double) total); - } - } - static double bytes_to_mb(size_t val) { return (double) val / (double) M; } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp index 86cbb25207f..8f11873950c 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp @@ -29,7 +29,7 @@ #include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" #include "gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp" -#include "gc/g1/suspendibleThreadSet.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "utilities/bitMap.inline.hpp" @@ -51,12 +51,8 @@ inline bool G1ConcurrentMark::mark_in_next_bitmap(HeapRegion* const hr, oop cons assert(!hr->is_continues_humongous(), "Should not try to mark object " PTR_FORMAT " in Humongous continues region %u above nTAMS " PTR_FORMAT, p2i(obj), hr->hrm_index(), p2i(hr->next_top_at_mark_start())); HeapWord* const obj_addr = (HeapWord*)obj; - // Dirty read to avoid CAS. - if (_nextMarkBitMap->is_marked(obj_addr)) { - return false; - } - return _nextMarkBitMap->par_mark(obj_addr); + return _next_mark_bitmap->par_mark(obj_addr); } #ifndef PRODUCT @@ -90,7 +86,7 @@ inline void G1CMTask::push(G1TaskQueueEntry task_entry) { assert(task_entry.is_array_slice() || !_g1h->is_on_master_free_list( _g1h->heap_region_containing(task_entry.obj())), "invariant"); assert(task_entry.is_array_slice() || !_g1h->is_obj_ill(task_entry.obj()), "invariant"); // FIXME!!! - assert(task_entry.is_array_slice() || _nextMarkBitMap->is_marked((HeapWord*)task_entry.obj()), "invariant"); + assert(task_entry.is_array_slice() || _next_mark_bitmap->is_marked((HeapWord*)task_entry.obj()), "invariant"); if (!_task_queue->push(task_entry)) { // The local task queue looks full. We need to push some entries @@ -138,7 +134,7 @@ inline bool G1CMTask::is_below_finger(oop obj, HeapWord* global_finger) const { template inline void G1CMTask::process_grey_task_entry(G1TaskQueueEntry task_entry) { assert(scan || (task_entry.is_oop() && task_entry.obj()->is_typeArray()), "Skipping scan of grey non-typeArray"); - assert(task_entry.is_array_slice() || _nextMarkBitMap->is_marked((HeapWord*)task_entry.obj()), + assert(task_entry.is_array_slice() || _next_mark_bitmap->is_marked((HeapWord*)task_entry.obj()), "Any stolen object should be a slice or marked"); if (scan) { @@ -211,14 +207,14 @@ inline void G1CMTask::deal_with_reference(oop obj) { make_reference_grey(obj); } -inline void G1ConcurrentMark::markPrev(oop p) { - assert(!_prevMarkBitMap->is_marked((HeapWord*) p), "sanity"); - _prevMarkBitMap->mark((HeapWord*) p); +inline void G1ConcurrentMark::mark_in_prev_bitmap(oop p) { + assert(!_prev_mark_bitmap->is_marked((HeapWord*) p), "sanity"); + _prev_mark_bitmap->mark((HeapWord*) p); } -bool G1ConcurrentMark::isPrevMarked(oop p) const { +bool G1ConcurrentMark::is_marked_in_prev_bitmap(oop p) const { assert(p != NULL && oopDesc::is_oop(p), "expected an oop"); - return _prevMarkBitMap->is_marked((HeapWord*)p); + return _prev_mark_bitmap->is_marked((HeapWord*)p); } inline bool G1ConcurrentMark::do_yield_check() { diff --git a/src/hotspot/share/gc/g1/g1DefaultPolicy.cpp b/src/hotspot/share/gc/g1/g1DefaultPolicy.cpp index 05253457cda..945db6e0491 100644 --- a/src/hotspot/share/gc/g1/g1DefaultPolicy.cpp +++ b/src/hotspot/share/gc/g1/g1DefaultPolicy.cpp @@ -538,7 +538,7 @@ CollectionSetChooser* G1DefaultPolicy::cset_chooser() const { } bool G1DefaultPolicy::about_to_start_mixed_phase() const { - return _g1->concurrent_mark()->cmThread()->during_cycle() || collector_state()->last_young_gc(); + return _g1->concurrent_mark()->cm_thread()->during_cycle() || collector_state()->last_young_gc(); } bool G1DefaultPolicy::need_to_start_conc_mark(const char* source, size_t alloc_word_size) { @@ -931,7 +931,7 @@ bool G1DefaultPolicy::force_initial_mark_if_outside_cycle(GCCause::Cause gc_caus // We actually check whether we are marking here and not if we are in a // reclamation phase. This means that we will schedule a concurrent mark // even while we are still in the process of reclaiming memory. - bool during_cycle = _g1->concurrent_mark()->cmThread()->during_cycle(); + bool during_cycle = _g1->concurrent_mark()->cm_thread()->during_cycle(); if (!during_cycle) { log_debug(gc, ergo)("Request concurrent cycle initiation (requested by GC cause). GC cause: %s", GCCause::to_string(gc_cause)); collector_state()->set_initiate_conc_mark_if_possible(true); @@ -1004,12 +1004,8 @@ void G1DefaultPolicy::record_concurrent_mark_cleanup_end() { record_pause(Cleanup, _mark_cleanup_start_sec, end_sec); } -double G1DefaultPolicy::reclaimable_bytes_perc(size_t reclaimable_bytes) const { - // Returns the given amount of reclaimable bytes (that represents - // the amount of reclaimable space still to be collected) as a - // percentage of the current heap capacity. - size_t capacity_bytes = _g1->capacity(); - return (double) reclaimable_bytes * 100.0 / (double) capacity_bytes; +double G1DefaultPolicy::reclaimable_bytes_percent(size_t reclaimable_bytes) const { + return percent_of(reclaimable_bytes, _g1->capacity()); } void G1DefaultPolicy::maybe_start_marking() { @@ -1083,15 +1079,15 @@ bool G1DefaultPolicy::next_gc_should_be_mixed(const char* true_action_str, // Is the amount of uncollected reclaimable space above G1HeapWastePercent? size_t reclaimable_bytes = cset_chooser()->remaining_reclaimable_bytes(); - double reclaimable_perc = reclaimable_bytes_perc(reclaimable_bytes); + double reclaimable_percent = reclaimable_bytes_percent(reclaimable_bytes); double threshold = (double) G1HeapWastePercent; - if (reclaimable_perc <= threshold) { + if (reclaimable_percent <= threshold) { log_debug(gc, ergo)("%s (reclaimable percentage not over threshold). candidate old regions: %u reclaimable: " SIZE_FORMAT " (%1.2f) threshold: " UINTX_FORMAT, - false_action_str, cset_chooser()->remaining_regions(), reclaimable_bytes, reclaimable_perc, G1HeapWastePercent); + false_action_str, cset_chooser()->remaining_regions(), reclaimable_bytes, reclaimable_percent, G1HeapWastePercent); return false; } log_debug(gc, ergo)("%s (candidate old regions available). candidate old regions: %u reclaimable: " SIZE_FORMAT " (%1.2f) threshold: " UINTX_FORMAT, - true_action_str, cset_chooser()->remaining_regions(), reclaimable_bytes, reclaimable_perc, G1HeapWastePercent); + true_action_str, cset_chooser()->remaining_regions(), reclaimable_bytes, reclaimable_percent, G1HeapWastePercent); return true; } diff --git a/src/hotspot/share/gc/g1/g1DefaultPolicy.hpp b/src/hotspot/share/gc/g1/g1DefaultPolicy.hpp index 81f35971d02..72db8153411 100644 --- a/src/hotspot/share/gc/g1/g1DefaultPolicy.hpp +++ b/src/hotspot/share/gc/g1/g1DefaultPolicy.hpp @@ -238,7 +238,10 @@ public: uint calc_min_old_cset_length() const; uint calc_max_old_cset_length() const; - double reclaimable_bytes_perc(size_t reclaimable_bytes) const; + // Returns the given amount of reclaimable bytes (that represents + // the amount of reclaimable space still to be collected) as a + // percentage of the current heap capacity. + double reclaimable_bytes_percent(size_t reclaimable_bytes) const; jlong collection_pause_end_millis() { return _collection_pause_end_millis; } diff --git a/src/hotspot/share/gc/g1/g1EvacFailure.cpp b/src/hotspot/share/gc/g1/g1EvacFailure.cpp index 4d698ec6218..d663f6be1c1 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailure.cpp +++ b/src/hotspot/share/gc/g1/g1EvacFailure.cpp @@ -110,8 +110,8 @@ public: // We consider all objects that we find self-forwarded to be // live. What we'll do is that we'll update the prev marking // info so that they are all under PTAMS and explicitly marked. - if (!_cm->isPrevMarked(obj)) { - _cm->markPrev(obj); + if (!_cm->is_marked_in_prev_bitmap(obj)) { + _cm->mark_in_prev_bitmap(obj); } if (_during_initial_mark) { // For the next marking info we'll only mark the @@ -181,7 +181,7 @@ public: #endif } } - _cm->clearRangePrevBitmap(mr); + _cm->clear_range_in_prev_bitmap(mr); } void zap_remainder() { diff --git a/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp b/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp index 007f62d3af4..5acd4c146f6 100644 --- a/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp +++ b/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -29,17 +29,17 @@ #include "runtime/atomic.hpp" inline void G1EvacStats::add_direct_allocated(size_t value) { - Atomic::add_ptr(value, &_direct_allocated); + Atomic::add(value, &_direct_allocated); } inline void G1EvacStats::add_region_end_waste(size_t value) { - Atomic::add_ptr(value, &_region_end_waste); - Atomic::add_ptr(1, &_regions_filled); + Atomic::add(value, &_region_end_waste); + Atomic::inc(&_regions_filled); } inline void G1EvacStats::add_failure_used_and_waste(size_t used, size_t waste) { - Atomic::add_ptr(used, &_failure_used); - Atomic::add_ptr(waste, &_failure_waste); + Atomic::add(used, &_failure_used); + Atomic::add(waste, &_failure_waste); } #endif // SHARE_VM_GC_G1_G1EVACSTATS_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp b/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp index 5fa79c87dfc..68e2a8eac03 100644 --- a/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp +++ b/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp @@ -51,9 +51,9 @@ size_t G1HeapSizingPolicy::expansion_amount() { assert(GCTimeRatio > 0, "we should have set it to a default value set_g1_gc_flags() " "if a user set it to 0"); - const double gc_overhead_perc = 100.0 * (1.0 / (1.0 + GCTimeRatio)); + const double gc_overhead_percent = 100.0 * (1.0 / (1.0 + GCTimeRatio)); - double threshold = gc_overhead_perc; + double threshold = gc_overhead_percent; size_t expand_bytes = 0; // If the heap is at less than half its maximum size, scale the threshold down, @@ -107,9 +107,9 @@ size_t G1HeapSizingPolicy::expansion_amount() { } else { double const MinScaleDownFactor = 0.2; double const MaxScaleUpFactor = 2; - double const StartScaleDownAt = gc_overhead_perc; - double const StartScaleUpAt = gc_overhead_perc * 1.5; - double const ScaleUpRange = gc_overhead_perc * 2.0; + double const StartScaleDownAt = gc_overhead_percent; + double const StartScaleUpAt = gc_overhead_percent * 1.5; + double const ScaleUpRange = gc_overhead_percent * 2.0; double ratio_delta; if (filled_history_buffer) { diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp index 8b2e0334333..b820d101469 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp @@ -161,18 +161,18 @@ class YoungRefCounterClosure : public OopClosure { void reset_count() { _count = 0; }; }; -class VerifyKlassClosure: public KlassClosure { +class VerifyCLDClosure: public CLDClosure { YoungRefCounterClosure _young_ref_counter_closure; OopClosure *_oop_closure; public: - VerifyKlassClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {} - void do_klass(Klass* k) { - k->oops_do(_oop_closure); + VerifyCLDClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {} + void do_cld(ClassLoaderData* cld) { + cld->oops_do(_oop_closure, false); _young_ref_counter_closure.reset_count(); - k->oops_do(&_young_ref_counter_closure); + cld->oops_do(&_young_ref_counter_closure, false); if (_young_ref_counter_closure.count() > 0) { - guarantee(k->has_modified_oops(), "Klass " PTR_FORMAT ", has young refs but is not dirty.", p2i(k)); + guarantee(cld->has_modified_oops(), "CLD " PTR_FORMAT ", has young %d refs but is not dirty.", p2i(cld), _young_ref_counter_closure.count()); } } }; @@ -390,8 +390,7 @@ void G1HeapVerifier::verify(VerifyOption vo) { log_debug(gc, verify)("Roots"); VerifyRootsClosure rootsCl(vo); - VerifyKlassClosure klassCl(_g1h, &rootsCl); - CLDToKlassAndOopClosure cldCl(&klassCl, &rootsCl, false); + VerifyCLDClosure cldCl(_g1h, &rootsCl); // We apply the relevant closures to all the oops in the // system dictionary, class loader data graph, the string table @@ -648,8 +647,8 @@ bool G1HeapVerifier::verify_no_bits_over_tams(const char* bitmap_name, const G1C } bool G1HeapVerifier::verify_bitmaps(const char* caller, HeapRegion* hr) { - const G1CMBitMap* const prev_bitmap = _g1h->concurrent_mark()->prevMarkBitMap(); - const G1CMBitMap* const next_bitmap = _g1h->concurrent_mark()->nextMarkBitMap(); + const G1CMBitMap* const prev_bitmap = _g1h->concurrent_mark()->prev_mark_bitmap(); + const G1CMBitMap* const next_bitmap = _g1h->concurrent_mark()->next_mark_bitmap(); HeapWord* ptams = hr->prev_top_at_mark_start(); HeapWord* ntams = hr->next_top_at_mark_start(); diff --git a/src/hotspot/share/gc/g1/g1HotCardCache.cpp b/src/hotspot/share/gc/g1/g1HotCardCache.cpp index 346b4d5128a..1895364dd5e 100644 --- a/src/hotspot/share/gc/g1/g1HotCardCache.cpp +++ b/src/hotspot/share/gc/g1/g1HotCardCache.cpp @@ -74,9 +74,9 @@ jbyte* G1HotCardCache::insert(jbyte* card_ptr) { // card_ptr in favor of the other option, which would be starting over. This // should be OK since card_ptr will likely be the older card already when/if // this ever happens. - jbyte* previous_ptr = (jbyte*)Atomic::cmpxchg_ptr(card_ptr, - &_hot_cache[masked_index], - current_ptr); + jbyte* previous_ptr = Atomic::cmpxchg(card_ptr, + &_hot_cache[masked_index], + current_ptr); return (previous_ptr == current_ptr) ? previous_ptr : card_ptr; } diff --git a/src/hotspot/share/gc/g1/g1IHOPControl.cpp b/src/hotspot/share/gc/g1/g1IHOPControl.cpp index 9b74d50a085..25396801ab4 100644 --- a/src/hotspot/share/gc/g1/g1IHOPControl.cpp +++ b/src/hotspot/share/gc/g1/g1IHOPControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -57,7 +57,7 @@ void G1IHOPControl::print() { log_debug(gc, ihop)("Basic information (value update), threshold: " SIZE_FORMAT "B (%1.2f), target occupancy: " SIZE_FORMAT "B, current occupancy: " SIZE_FORMAT "B, " "recent allocation size: " SIZE_FORMAT "B, recent allocation duration: %1.2fms, recent old gen allocation rate: %1.2fB/s, recent marking phase length: %1.2fms", cur_conc_mark_start_threshold, - cur_conc_mark_start_threshold * 100.0 / _target_occupancy, + percent_of(cur_conc_mark_start_threshold, _target_occupancy), _target_occupancy, G1CollectedHeap::heap()->used(), _last_allocated_bytes, diff --git a/src/hotspot/share/gc/g1/g1MMUTracker.cpp b/src/hotspot/share/gc/g1/g1MMUTracker.cpp index fdb99afe7b7..e3e522179e9 100644 --- a/src/hotspot/share/gc/g1/g1MMUTracker.cpp +++ b/src/hotspot/share/gc/g1/g1MMUTracker.cpp @@ -29,8 +29,6 @@ #include "runtime/mutexLocker.hpp" #include "utilities/ostream.hpp" -#define _DISABLE_MMU 0 - // can't rely on comparing doubles with tolerating a small margin for error #define SMALL_MARGIN 0.0000001 #define is_double_leq_0(_value) ( (_value) < SMALL_MARGIN ) @@ -119,9 +117,6 @@ void G1MMUTrackerQueue::add_pause(double start, double end) { // of other places (debugging) double G1MMUTrackerQueue::when_sec(double current_time, double pause_time) { - if (_DISABLE_MMU) - return 0.0; - MutexLockerEx x(MMUTracker_lock, Mutex::_no_safepoint_check_flag); remove_expired_entries(current_time); diff --git a/src/hotspot/share/gc/g1/g1MarkSweep.cpp b/src/hotspot/share/gc/g1/g1MarkSweep.cpp index aad593b8c20..9fd8fa62790 100644 --- a/src/hotspot/share/gc/g1/g1MarkSweep.cpp +++ b/src/hotspot/share/gc/g1/g1MarkSweep.cpp @@ -43,6 +43,7 @@ #include "gc/shared/modRefBarrierSet.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/space.hpp" +#include "gc/shared/weakProcessor.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" @@ -184,6 +185,11 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading, // This is the point where the entire marking should have completed. assert(GenMarkSweep::_marking_stack.is_empty(), "Marking should have completed"); + { + GCTraceTime(Debug, gc, phases) trace("Weak Processing", gc_timer()); + WeakProcessor::weak_oops_do(&GenMarkSweep::is_alive, &do_nothing_cl); + } + if (ClassUnloading) { GCTraceTime(Debug, gc, phases) trace("Class Unloading", gc_timer()); @@ -272,7 +278,7 @@ void G1MarkSweep::mark_sweep_phase3() { // Now adjust pointers in remaining weak roots. (All of which should // have been cleared if they pointed to non-surviving objects.) - JNIHandles::weak_oops_do(&GenMarkSweep::adjust_pointer_closure); + WeakProcessor::oops_do(&GenMarkSweep::adjust_pointer_closure); if (G1StringDedup::is_enabled()) { G1StringDedup::oops_do(&GenMarkSweep::adjust_pointer_closure); diff --git a/src/hotspot/share/gc/g1/g1OopClosures.cpp b/src/hotspot/share/gc/g1/g1OopClosures.cpp index 9b04478f2d7..94a7da8b722 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.cpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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 @@ -34,7 +34,7 @@ G1ParCopyHelper::G1ParCopyHelper(G1CollectedHeap* g1, G1ParScanThreadState* par _g1(g1), _par_scan_state(par_scan_state), _worker_id(par_scan_state->worker_id()), - _scanned_klass(NULL), + _scanned_cld(NULL), _cm(_g1->concurrent_mark()) { } @@ -42,20 +42,20 @@ G1ScanClosureBase::G1ScanClosureBase(G1CollectedHeap* g1, G1ParScanThreadState* _g1(g1), _par_scan_state(par_scan_state), _from(NULL) { } -void G1KlassScanClosure::do_klass(Klass* klass) { - // If the klass has not been dirtied we know that there's +void G1CLDScanClosure::do_cld(ClassLoaderData* cld) { + // If the class loader data has not been dirtied we know that there's // no references into the young gen and we can skip it. - if (!_process_only_dirty || klass->has_modified_oops()) { - // Clean the klass since we're going to scavenge all the metadata. - klass->clear_modified_oops(); + if (!_process_only_dirty || cld->has_modified_oops()) { - // Tell the closure that this klass is the Klass to scavenge + // Tell the closure that this class loader data is the CLD to scavenge // and is the one to dirty if oops are left pointing into the young gen. - _closure->set_scanned_klass(klass); + _closure->set_scanned_cld(cld); - klass->oops_do(_closure); + // Clean the cld since we're going to scavenge all the metadata. + // Clear modified oops only if this cld is claimed. + cld->oops_do(_closure, _must_claim, /*clear_modified_oops*/true); - _closure->set_scanned_klass(NULL); + _closure->set_scanned_cld(NULL); } _count++; } diff --git a/src/hotspot/share/gc/g1/g1OopClosures.hpp b/src/hotspot/share/gc/g1/g1OopClosures.hpp index 20a2bd5252b..4d961ac946e 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.hpp @@ -107,7 +107,7 @@ protected: G1CollectedHeap* _g1; G1ParScanThreadState* _par_scan_state; uint _worker_id; // Cache value from par_scan_state. - Klass* _scanned_klass; + ClassLoaderData* _scanned_cld; G1ConcurrentMark* _cm; // Mark the object if it's not already marked. This is used to mark @@ -124,13 +124,13 @@ protected: ~G1ParCopyHelper() { } public: - void set_scanned_klass(Klass* k) { _scanned_klass = k; } - template inline void do_klass_barrier(T* p, oop new_obj); + void set_scanned_cld(ClassLoaderData* cld) { _scanned_cld = cld; } + inline void do_cld_barrier(oop new_obj); }; enum G1Barrier { G1BarrierNone, - G1BarrierKlass + G1BarrierCLD }; enum G1Mark { @@ -150,14 +150,16 @@ public: virtual void do_oop(narrowOop* p) { do_oop_work(p); } }; -class G1KlassScanClosure : public KlassClosure { +class G1CLDScanClosure : public CLDClosure { G1ParCopyHelper* _closure; bool _process_only_dirty; + bool _must_claim; int _count; public: - G1KlassScanClosure(G1ParCopyHelper* closure, bool process_only_dirty) - : _process_only_dirty(process_only_dirty), _closure(closure), _count(0) {} - void do_klass(Klass* klass); + G1CLDScanClosure(G1ParCopyHelper* closure, + bool process_only_dirty, bool must_claim) + : _process_only_dirty(process_only_dirty), _must_claim(must_claim), _closure(closure), _count(0) {} + void do_cld(ClassLoaderData* cld); }; // Closure for iterating over object fields during concurrent marking diff --git a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp index 017b2df5c13..e3b6887880c 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp @@ -195,10 +195,9 @@ inline void G1ScanObjsDuringScanRSClosure::do_oop_nv(T* p) { } } -template -void G1ParCopyHelper::do_klass_barrier(T* p, oop new_obj) { +void G1ParCopyHelper::do_cld_barrier(oop new_obj) { if (_g1->heap_region_containing(new_obj)->is_young()) { - _scanned_klass->record_modified_oops(); + _scanned_cld->record_modified_oops(); } } @@ -249,8 +248,8 @@ void G1ParCopyClosure::do_oop_work(T* p) { mark_forwarded_object(obj, forwardee); } - if (barrier == G1BarrierKlass) { - do_klass_barrier(p, forwardee); + if (barrier == G1BarrierCLD) { + do_cld_barrier(forwardee); } } else { if (state.is_humongous()) { @@ -267,5 +266,4 @@ void G1ParCopyClosure::do_oop_work(T* p) { } } } - #endif // SHARE_VM_GC_G1_G1OOPCLOSURES_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp index 82931884517..bdf01d36940 100644 --- a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp +++ b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp @@ -251,7 +251,7 @@ public: virtual void work(uint worker_id) { size_t const actual_chunk_size = MAX2(chunk_size(), _page_size); while (true) { - char* touch_addr = (char*)Atomic::add_ptr((intptr_t)actual_chunk_size, (volatile void*) &_cur_addr) - actual_chunk_size; + char* touch_addr = Atomic::add(actual_chunk_size, &_cur_addr) - actual_chunk_size; if (touch_addr < _start_addr || touch_addr >= _end_addr) { break; } diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index ec1ea47abb9..756191d84a7 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -89,7 +89,7 @@ public: // Returns the given amount of uncollected reclaimable space // as a percentage of the current heap capacity. - virtual double reclaimable_bytes_perc(size_t reclaimable_bytes) const = 0; + virtual double reclaimable_bytes_percent(size_t reclaimable_bytes) const = 0; virtual ~G1Policy() {} diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 0c504db5998..76f54d85004 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -36,8 +36,8 @@ #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionManager.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" -#include "gc/g1/suspendibleThreadSet.hpp" #include "gc/shared/gcTraceTime.inline.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1SATBCardTableModRefBS.hpp b/src/hotspot/share/gc/g1/g1SATBCardTableModRefBS.hpp index 0cd8970a89b..65315484aeb 100644 --- a/src/hotspot/share/gc/g1/g1SATBCardTableModRefBS.hpp +++ b/src/hotspot/share/gc/g1/g1SATBCardTableModRefBS.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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 @@ -54,8 +54,6 @@ public: // pre-marking object graph. static void enqueue(oop pre_val); - virtual bool has_write_ref_pre_barrier() { return true; } - // We export this to make it available in cases where the static // type of the barrier set is known. Note that it is non-virtual. template inline void inline_write_ref_field_pre(T* field, oop newVal); @@ -63,9 +61,6 @@ public: // These are the more general virtual versions. inline virtual void write_ref_field_pre_work(oop* field, oop new_val); inline virtual void write_ref_field_pre_work(narrowOop* field, oop new_val); - virtual void write_ref_field_pre_work(void* field, oop new_val) { - guarantee(false, "Not needed"); - } template void write_ref_array_pre_work(T* dst, int count); virtual void write_ref_array_pre(oop* dst, int count, bool dest_uninitialized); diff --git a/src/hotspot/share/gc/g1/g1SharedClosures.hpp b/src/hotspot/share/gc/g1/g1SharedClosures.hpp index 2c9352394ae..38c54f5b7d4 100644 --- a/src/hotspot/share/gc/g1/g1SharedClosures.hpp +++ b/src/hotspot/share/gc/g1/g1SharedClosures.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -34,18 +34,17 @@ class G1ParScanThreadState; template class G1SharedClosures VALUE_OBJ_CLASS_SPEC { public: - G1ParCopyClosure _oops; - G1ParCopyClosure _oop_in_klass; - G1KlassScanClosure _klass_in_cld_closure; - CLDToKlassAndOopClosure _clds; - G1CodeBlobClosure _codeblobs; - BufferingOopClosure _buffered_oops; + G1ParCopyClosure _oops; + G1ParCopyClosure _oops_in_cld; - G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty_klasses, bool must_claim_cld) : + G1CLDScanClosure _clds; + G1CodeBlobClosure _codeblobs; + BufferingOopClosure _buffered_oops; + + G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty, bool must_claim_cld) : _oops(g1h, pss), - _oop_in_klass(g1h, pss), - _klass_in_cld_closure(&_oop_in_klass, process_only_dirty_klasses), - _clds(&_klass_in_cld_closure, &_oops, must_claim_cld), + _oops_in_cld(g1h, pss), + _clds(&_oops_in_cld, process_only_dirty, must_claim_cld), _codeblobs(&_oops), _buffered_oops(&_oops) {} }; diff --git a/src/hotspot/share/gc/g1/g1StringDedup.cpp b/src/hotspot/share/gc/g1/g1StringDedup.cpp index 9819d3eb26a..5d303eb8189 100644 --- a/src/hotspot/share/gc/g1/g1StringDedup.cpp +++ b/src/hotspot/share/gc/g1/g1StringDedup.cpp @@ -203,12 +203,12 @@ G1StringDedupUnlinkOrOopsDoClosure::~G1StringDedupUnlinkOrOopsDoClosure() { // Atomically claims the next available queue for exclusive access by // the current thread. Returns the queue number of the claimed queue. size_t G1StringDedupUnlinkOrOopsDoClosure::claim_queue() { - return (size_t)Atomic::add_ptr(1, &_next_queue) - 1; + return Atomic::add((size_t)1, &_next_queue) - 1; } // Atomically claims the next available table partition for exclusive // access by the current thread. Returns the table bucket number where // the claimed partition starts. size_t G1StringDedupUnlinkOrOopsDoClosure::claim_table_partition(size_t partition_size) { - return (size_t)Atomic::add_ptr(partition_size, &_next_bucket) - partition_size; + return Atomic::add(partition_size, &_next_bucket) - partition_size; } diff --git a/src/hotspot/share/gc/g1/g1StringDedupQueue.cpp b/src/hotspot/share/gc/g1/g1StringDedupQueue.cpp index b029c3f2b40..546f33d9120 100644 --- a/src/hotspot/share/gc/g1/g1StringDedupQueue.cpp +++ b/src/hotspot/share/gc/g1/g1StringDedupQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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 @@ -90,7 +90,7 @@ void G1StringDedupQueue::push(uint worker_id, oop java_string) { } } else { // Queue is full, drop the string and update the statistics - Atomic::inc_ptr(&_queue->_dropped); + Atomic::inc(&_queue->_dropped); } } diff --git a/src/hotspot/share/gc/g1/g1StringDedupStat.cpp b/src/hotspot/share/gc/g1/g1StringDedupStat.cpp index 6443f6e8a92..7c1a60ad5e1 100644 --- a/src/hotspot/share/gc/g1/g1StringDedupStat.cpp +++ b/src/hotspot/share/gc/g1/g1StringDedupStat.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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 @@ -82,7 +82,7 @@ void G1StringDedupStat::print_end(const G1StringDedupStat& last_stat, const G1St if (total_stat._new_bytes > 0) { // Avoid division by zero - total_deduped_bytes_percent = (double)total_stat._deduped_bytes / (double)total_stat._new_bytes * 100.0; + total_deduped_bytes_percent = percent_of(total_stat._deduped_bytes, total_stat._new_bytes); } log_info(gc, stringdedup)( @@ -100,48 +100,16 @@ void G1StringDedupStat::print_end(const G1StringDedupStat& last_stat, const G1St } void G1StringDedupStat::print_statistics(const G1StringDedupStat& stat, bool total) { - double young_percent = 0.0; - double old_percent = 0.0; - double skipped_percent = 0.0; - double hashed_percent = 0.0; - double known_percent = 0.0; - double new_percent = 0.0; - double deduped_percent = 0.0; - double deduped_bytes_percent = 0.0; - double deduped_young_percent = 0.0; - double deduped_young_bytes_percent = 0.0; - double deduped_old_percent = 0.0; - double deduped_old_bytes_percent = 0.0; - - if (stat._inspected > 0) { - // Avoid division by zero - skipped_percent = (double)stat._skipped / (double)stat._inspected * 100.0; - hashed_percent = (double)stat._hashed / (double)stat._inspected * 100.0; - known_percent = (double)stat._known / (double)stat._inspected * 100.0; - new_percent = (double)stat._new / (double)stat._inspected * 100.0; - } - - if (stat._new > 0) { - // Avoid division by zero - deduped_percent = (double)stat._deduped / (double)stat._new * 100.0; - } - - if (stat._deduped > 0) { - // Avoid division by zero - deduped_young_percent = (double)stat._deduped_young / (double)stat._deduped * 100.0; - deduped_old_percent = (double)stat._deduped_old / (double)stat._deduped * 100.0; - } - - if (stat._new_bytes > 0) { - // Avoid division by zero - deduped_bytes_percent = (double)stat._deduped_bytes / (double)stat._new_bytes * 100.0; - } - - if (stat._deduped_bytes > 0) { - // Avoid division by zero - deduped_young_bytes_percent = (double)stat._deduped_young_bytes / (double)stat._deduped_bytes * 100.0; - deduped_old_bytes_percent = (double)stat._deduped_old_bytes / (double)stat._deduped_bytes * 100.0; - } + double skipped_percent = percent_of(stat._skipped, stat._inspected); + double hashed_percent = percent_of(stat._hashed, stat._inspected); + double known_percent = percent_of(stat._known, stat._inspected); + double new_percent = percent_of(stat._new, stat._inspected); + double deduped_percent = percent_of(stat._deduped, stat._new); + double deduped_bytes_percent = percent_of(stat._deduped_bytes, stat._new_bytes); + double deduped_young_percent = percent_of(stat._deduped_young, stat._deduped); + double deduped_young_bytes_percent = percent_of(stat._deduped_young_bytes, stat._deduped_bytes); + double deduped_old_percent = percent_of(stat._deduped_old, stat._deduped); + double deduped_old_bytes_percent = percent_of(stat._deduped_old_bytes, stat._deduped_bytes); if (total) { log_debug(gc, stringdedup)( diff --git a/src/hotspot/share/gc/g1/g1StringDedupTable.cpp b/src/hotspot/share/gc/g1/g1StringDedupTable.cpp index 1554ef458ba..4b236f9cae0 100644 --- a/src/hotspot/share/gc/g1/g1StringDedupTable.cpp +++ b/src/hotspot/share/gc/g1/g1StringDedupTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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 @@ -616,7 +616,7 @@ void G1StringDedupTable::print_statistics() { G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry))); log.debug(" Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT, _table->_size, _min_size, _max_size); log.debug(" Entries: " UINTX_FORMAT ", Load: " G1_STRDEDUP_PERCENT_FORMAT_NS ", Cached: " UINTX_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT, - _table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed); + _table->_entries, percent_of(_table->_entries, _table->_size), _entry_cache->size(), _entries_added, _entries_removed); log.debug(" Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS ")", _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0); log.debug(" Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: 0x%x", _rehash_count, _rehash_threshold, _table->_hash_seed); diff --git a/src/hotspot/share/gc/g1/g1StringDedupThread.cpp b/src/hotspot/share/gc/g1/g1StringDedupThread.cpp index f0b25d3c6a9..60ec044b3ed 100644 --- a/src/hotspot/share/gc/g1/g1StringDedupThread.cpp +++ b/src/hotspot/share/gc/g1/g1StringDedupThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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 @@ -28,7 +28,7 @@ #include "gc/g1/g1StringDedupQueue.hpp" #include "gc/g1/g1StringDedupTable.hpp" #include "gc/g1/g1StringDedupThread.hpp" -#include "gc/g1/suspendibleThreadSet.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" diff --git a/src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp b/src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp index d94dbd868e3..4473564b38b 100644 --- a/src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp +++ b/src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -29,7 +29,7 @@ #include "gc/g1/g1YoungRemSetSamplingThread.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" -#include "gc/g1/suspendibleThreadSet.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "runtime/mutexLocker.hpp" G1YoungRemSetSamplingThread::G1YoungRemSetSamplingThread() : diff --git a/src/hotspot/share/gc/g1/g1_globals.hpp b/src/hotspot/share/gc/g1/g1_globals.hpp index 35b5b4580de..d69c1712433 100644 --- a/src/hotspot/share/gc/g1/g1_globals.hpp +++ b/src/hotspot/share/gc/g1/g1_globals.hpp @@ -61,10 +61,6 @@ "Confidence level for MMU/pause predictions") \ range(0, 100) \ \ - develop(intx, G1MarkingOverheadPercent, 0, \ - "Overhead of concurrent marking") \ - range(0, 100) \ - \ diagnostic(intx, G1SummarizeRSetStatsPeriod, 0, \ "The period (in number of GCs) at which we will generate " \ "update buffer processing info " \ diff --git a/src/hotspot/share/gc/g1/heapRegion.inline.hpp b/src/hotspot/share/gc/g1/heapRegion.inline.hpp index 58641f381f1..bad8d41fc09 100644 --- a/src/hotspot/share/gc/g1/heapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/heapRegion.inline.hpp @@ -59,7 +59,7 @@ inline HeapWord* G1ContiguousSpace::par_allocate_impl(size_t min_word_size, size_t want_to_allocate = MIN2(available, desired_word_size); if (want_to_allocate >= min_word_size) { HeapWord* new_top = obj + want_to_allocate; - HeapWord* result = (HeapWord*)Atomic::cmpxchg_ptr(new_top, top_addr(), obj); + HeapWord* result = Atomic::cmpxchg(new_top, top_addr(), obj); // result can be one of two: // the old top value: the exchange succeeded // otherwise: the new value of the top is returned. @@ -177,7 +177,7 @@ inline size_t HeapRegion::block_size(const HeapWord *addr) const { return oop(addr)->size(); } - return block_size_using_bitmap(addr, G1CollectedHeap::heap()->concurrent_mark()->prevMarkBitMap()); + return block_size_using_bitmap(addr, G1CollectedHeap::heap()->concurrent_mark()->prev_mark_bitmap()); } inline HeapWord* HeapRegion::par_allocate_no_bot_updates(size_t min_word_size, @@ -334,7 +334,7 @@ bool HeapRegion::oops_on_card_seq_iterate_careful(MemRegion mr, } #endif - const G1CMBitMap* const bitmap = g1h->concurrent_mark()->prevMarkBitMap(); + const G1CMBitMap* const bitmap = g1h->concurrent_mark()->prev_mark_bitmap(); do { oop obj = oop(cur); assert(oopDesc::is_oop(obj, true), "Not an oop at " PTR_FORMAT, p2i(cur)); diff --git a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp index a456dbd8ad7..6ea136ad40f 100644 --- a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp @@ -113,9 +113,7 @@ protected: public: - HeapRegion* hr() const { - return (HeapRegion*) OrderAccess::load_ptr_acquire(&_hr); - } + HeapRegion* hr() const { return OrderAccess::load_acquire(&_hr); } jint occupied() const { // Overkill, but if we ever need it... @@ -133,7 +131,7 @@ public: _bm.clear(); // Make sure that the bitmap clearing above has been finished before publishing // this PRT to concurrent threads. - OrderAccess::release_store_ptr(&_hr, hr); + OrderAccess::release_store(&_hr, hr); } void add_reference(OopOrNarrowOopStar from) { @@ -182,7 +180,7 @@ public: while (true) { PerRegionTable* fl = _free_list; last->set_next(fl); - PerRegionTable* res = (PerRegionTable*) Atomic::cmpxchg_ptr(prt, &_free_list, fl); + PerRegionTable* res = Atomic::cmpxchg(prt, &_free_list, fl); if (res == fl) { return; } @@ -199,9 +197,7 @@ public: PerRegionTable* fl = _free_list; while (fl != NULL) { PerRegionTable* nxt = fl->next(); - PerRegionTable* res = - (PerRegionTable*) - Atomic::cmpxchg_ptr(nxt, &_free_list, fl); + PerRegionTable* res = Atomic::cmpxchg(nxt, &_free_list, fl); if (res == fl) { fl->init(hr, true); return fl; @@ -416,7 +412,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, uint tid) { // some mark bits may not yet seem cleared or a 'later' update // performed by a concurrent thread could be undone when the // zeroing becomes visible). This requires store ordering. - OrderAccess::release_store_ptr((volatile PerRegionTable*)&_fine_grain_regions[ind], prt); + OrderAccess::release_store(&_fine_grain_regions[ind], prt); _n_fine_entries++; if (G1HRRSUseSparseTable) { diff --git a/src/hotspot/share/gc/g1/heapRegionType.hpp b/src/hotspot/share/gc/g1/heapRegionType.hpp index e0829c00c8c..f6900d2070f 100644 --- a/src/hotspot/share/gc/g1/heapRegionType.hpp +++ b/src/hotspot/share/gc/g1/heapRegionType.hpp @@ -32,6 +32,8 @@ assert(is_valid((tag)), "invalid HR type: %u", (uint) (tag)) class HeapRegionType VALUE_OBJ_CLASS_SPEC { +friend class VMStructs; + private: // We encode the value of the heap region type so the generation can be // determined quickly. The tag is split into two parts: diff --git a/src/hotspot/share/gc/g1/sparsePRT.cpp b/src/hotspot/share/gc/g1/sparsePRT.cpp index 1ef606e749b..6131f3cd692 100644 --- a/src/hotspot/share/gc/g1/sparsePRT.cpp +++ b/src/hotspot/share/gc/g1/sparsePRT.cpp @@ -292,9 +292,7 @@ void SparsePRT::add_to_expanded_list(SparsePRT* sprt) { SparsePRT* hd = _head_expanded_list; while (true) { sprt->_next_expanded = hd; - SparsePRT* res = - (SparsePRT*) - Atomic::cmpxchg_ptr(sprt, &_head_expanded_list, hd); + SparsePRT* res = Atomic::cmpxchg(sprt, &_head_expanded_list, hd); if (res == hd) return; else hd = res; } @@ -305,9 +303,7 @@ SparsePRT* SparsePRT::get_from_expanded_list() { SparsePRT* hd = _head_expanded_list; while (hd != NULL) { SparsePRT* next = hd->next_expanded(); - SparsePRT* res = - (SparsePRT*) - Atomic::cmpxchg_ptr(next, &_head_expanded_list, hd); + SparsePRT* res = Atomic::cmpxchg(next, &_head_expanded_list, hd); if (res == hd) { hd->set_next_expanded(NULL); return hd; diff --git a/src/hotspot/share/gc/g1/vmStructs_g1.hpp b/src/hotspot/share/gc/g1/vmStructs_g1.hpp index 5026d6ee7ac..19f338dc20c 100644 --- a/src/hotspot/share/gc/g1/vmStructs_g1.hpp +++ b/src/hotspot/share/gc/g1/vmStructs_g1.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -35,6 +35,10 @@ static_field(HeapRegion, GrainBytes, size_t) \ static_field(HeapRegion, LogOfHRGrainBytes, int) \ \ + nonstatic_field(HeapRegion, _type, HeapRegionType) \ + \ + nonstatic_field(HeapRegionType, _tag, HeapRegionType::Tag volatile) \ + \ nonstatic_field(G1ContiguousSpace, _top, HeapWord* volatile) \ \ nonstatic_field(G1HeapRegionTable, _base, address) \ @@ -67,9 +71,16 @@ #define VM_INT_CONSTANTS_G1(declare_constant, declare_constant_with_value) \ + declare_constant(HeapRegionType::FreeTag) \ + declare_constant(HeapRegionType::YoungMask) \ + declare_constant(HeapRegionType::HumongousMask) \ + declare_constant(HeapRegionType::PinnedMask) \ + declare_constant(HeapRegionType::OldMask) -#define VM_TYPES_G1(declare_type, declare_toplevel_type) \ +#define VM_TYPES_G1(declare_type, \ + declare_toplevel_type, \ + declare_integer_type) \ \ declare_toplevel_type(G1HeapRegionTable) \ \ @@ -81,9 +92,12 @@ declare_toplevel_type(HeapRegionSetBase) \ declare_toplevel_type(G1MonitoringSupport) \ declare_toplevel_type(PtrQueue) \ + declare_toplevel_type(HeapRegionType) \ \ declare_toplevel_type(G1CollectedHeap*) \ declare_toplevel_type(HeapRegion*) \ declare_toplevel_type(G1MonitoringSupport*) \ + \ + declare_integer_type(HeapRegionType::Tag volatile) #endif // SHARE_VM_GC_G1_VMSTRUCTS_G1_HPP diff --git a/src/hotspot/share/gc/parallel/gcTaskThread.cpp b/src/hotspot/share/gc/parallel/gcTaskThread.cpp index e300f8c2309..440f5124539 100644 --- a/src/hotspot/share/gc/parallel/gcTaskThread.cpp +++ b/src/hotspot/share/gc/parallel/gcTaskThread.cpp @@ -77,8 +77,7 @@ GCTaskTimeStamp* GCTaskThread::time_stamp_at(uint index) { if (_time_stamps == NULL) { // We allocate the _time_stamps array lazily since logging can be enabled dynamically GCTaskTimeStamp* time_stamps = NEW_C_HEAP_ARRAY(GCTaskTimeStamp, GCTaskTimeStampEntries, mtGC); - void* old = Atomic::cmpxchg_ptr(time_stamps, &_time_stamps, NULL); - if (old != NULL) { + if (Atomic::cmpxchg(time_stamps, &_time_stamps, (GCTaskTimeStamp*)NULL) != NULL) { // Someone already setup the time stamps FREE_C_HEAP_ARRAY(GCTaskTimeStamp, time_stamps); } diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp index e765d0f2d90..120ff95bae5 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2017, 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 @@ -862,7 +862,7 @@ HeapWord* MutableNUMASpace::cas_allocate(size_t size) { if (p != NULL) { HeapWord* cur_top, *cur_chunk_top = p + size; while ((cur_top = top()) < cur_chunk_top) { // Keep _top updated. - if (Atomic::cmpxchg_ptr(cur_chunk_top, top_addr(), cur_top) == cur_top) { + if (Atomic::cmpxchg(cur_chunk_top, top_addr(), cur_top) == cur_top) { break; } } diff --git a/src/hotspot/share/gc/parallel/mutableSpace.cpp b/src/hotspot/share/gc/parallel/mutableSpace.cpp index c0e95e3505e..05b7fd19aec 100644 --- a/src/hotspot/share/gc/parallel/mutableSpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableSpace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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 @@ -192,7 +192,7 @@ HeapWord* MutableSpace::cas_allocate(size_t size) { HeapWord* obj = top(); if (pointer_delta(end(), obj) >= size) { HeapWord* new_top = obj + size; - HeapWord* result = (HeapWord*)Atomic::cmpxchg_ptr(new_top, top_addr(), obj); + HeapWord* result = Atomic::cmpxchg(new_top, top_addr(), obj); // result can be one of two: // the old top value: the exchange succeeded // otherwise: the new value of the top is returned. @@ -211,7 +211,7 @@ HeapWord* MutableSpace::cas_allocate(size_t size) { // Try to deallocate previous allocation. Returns true upon success. bool MutableSpace::cas_deallocate(HeapWord *obj, size_t size) { HeapWord* expected_top = obj + size; - return (HeapWord*)Atomic::cmpxchg_ptr(obj, top_addr(), expected_top) == expected_top; + return Atomic::cmpxchg(obj, top_addr(), expected_top) == expected_top; } void MutableSpace::oop_iterate_no_header(OopClosure* cl) { diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp index 8696160c880..6b9888d6a2f 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, 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 @@ -89,8 +89,8 @@ ParMarkBitMap::mark_obj(HeapWord* addr, size_t size) const idx_t end_bit = addr_to_bit(addr + size - 1); bool end_bit_ok = _end_bits.par_set_bit(end_bit); assert(end_bit_ok, "concurrency problem"); - DEBUG_ONLY(Atomic::inc_ptr(&mark_bitmap_count)); - DEBUG_ONLY(Atomic::add_ptr(size, &mark_bitmap_size)); + DEBUG_ONLY(Atomic::inc(&mark_bitmap_count)); + DEBUG_ONLY(Atomic::add(size, &mark_bitmap_size)); return true; } return false; diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index dba08b5a92a..27fcf5c1adc 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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,6 +23,7 @@ */ #include "precompiled.hpp" +#include "code/codeCache.hpp" #include "gc/parallel/adjoiningGenerations.hpp" #include "gc/parallel/adjoiningVirtualSpaces.hpp" #include "gc/parallel/cardTableExtension.hpp" @@ -169,10 +170,6 @@ bool ParallelScavengeHeap::is_in_reserved(const void* p) const { return young_gen()->is_in_reserved(p) || old_gen()->is_in_reserved(p); } -bool ParallelScavengeHeap::is_scavengable(const void* addr) { - return is_in_young((oop)addr); -} - // There are two levels of allocation policy here. // // When an allocation request fails, the requesting thread must invoke a VM @@ -574,16 +571,10 @@ void ParallelScavengeHeap::print_gc_threads_on(outputStream* st) const { } void ParallelScavengeHeap::print_tracing_info() const { - if (TraceYoungGenTime) { - double time = PSScavenge::accumulated_time()->seconds(); - tty->print_cr("[Accumulated GC generation 0 time %3.7f secs]", time); - } - if (TraceOldGenTime) { - double time = UseParallelOldGC ? PSParallelCompact::accumulated_time()->seconds() : PSMarkSweep::accumulated_time()->seconds(); - tty->print_cr("[Accumulated GC generation 1 time %3.7f secs]", time); - } - AdaptiveSizePolicyOutput::print(); + log_debug(gc, heap, exit)("Accumulated young generation GC time %3.7f secs", PSScavenge::accumulated_time()->seconds()); + log_debug(gc, heap, exit)("Accumulated old generation GC time %3.7f secs", + UseParallelOldGC ? PSParallelCompact::accumulated_time()->seconds() : PSMarkSweep::accumulated_time()->seconds()); } @@ -671,3 +662,15 @@ void ParallelScavengeHeap::gen_mangle_unused_area() { } } #endif + +bool ParallelScavengeHeap::is_scavengable(oop obj) { + return is_in_young(obj); +} + +void ParallelScavengeHeap::register_nmethod(nmethod* nm) { + CodeCache::register_scavenge_root_nmethod(nm); +} + +void ParallelScavengeHeap::verify_nmethod(nmethod* nm) { + CodeCache::verify_scavenge_root_nmethod(nm); +} diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index e83cb3e5f2f..bfdc55f07f7 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -134,7 +134,9 @@ class ParallelScavengeHeap : public CollectedHeap { // can be moved in a partial collection. For currently implemented // generational collectors that means during a collection of // the young gen. - virtual bool is_scavengable(const void* addr); + virtual bool is_scavengable(oop obj); + virtual void register_nmethod(nmethod* nm); + virtual void verify_nmethod(nmethod* nmethod); size_t max_capacity() const; diff --git a/src/hotspot/share/gc/parallel/pcTasks.cpp b/src/hotspot/share/gc/parallel/pcTasks.cpp index 8cae47c23ef..f5db42d6d09 100644 --- a/src/hotspot/share/gc/parallel/pcTasks.cpp +++ b/src/hotspot/share/gc/parallel/pcTasks.cpp @@ -81,7 +81,6 @@ void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) { ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); ParCompactionManager::MarkAndPushClosure mark_and_push_closure(cm); - ParCompactionManager::FollowKlassClosure follow_klass_closure(&mark_and_push_closure); switch (_root_type) { case universe: @@ -117,7 +116,7 @@ void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) { break; case class_loader_data: - ClassLoaderDataGraph::always_strong_oops_do(&mark_and_push_closure, &follow_klass_closure, true); + ClassLoaderDataGraph::always_strong_oops_do(&mark_and_push_closure, true); break; case code_cache: diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.hpp index 9eb8bceff57..4690b1d9e3e 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, 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 @@ -196,17 +196,6 @@ private: FollowStackClosure(ParCompactionManager* cm) : _compaction_manager(cm) { } virtual void do_void(); }; - - // The one and only place to start following the classes. - // Should only be applied to the ClassLoaderData klasses list. - class FollowKlassClosure : public KlassClosure { - private: - MarkAndPushClosure* _mark_and_push_closure; - public: - FollowKlassClosure(MarkAndPushClosure* mark_and_push_closure) : - _mark_and_push_closure(mark_and_push_closure) { } - void do_klass(Klass* klass); - }; }; inline ParCompactionManager* ParCompactionManager::manager_array(uint index) { diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp index 7d844c08db7..1376fa65c8e 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2017, 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 @@ -98,15 +98,10 @@ inline void ParCompactionManager::FollowStackClosure::do_void() { _compaction_manager->follow_marking_stacks(); } -inline void ParCompactionManager::FollowKlassClosure::do_klass(Klass* klass) { - klass->oops_do(_mark_and_push_closure); -} - inline void ParCompactionManager::follow_class_loader(ClassLoaderData* cld) { MarkAndPushClosure mark_and_push_closure(this); - FollowKlassClosure follow_klass_closure(&mark_and_push_closure); - cld->oops_do(&mark_and_push_closure, &follow_klass_closure, true); + cld->oops_do(&mark_and_push_closure, true); } inline void ParCompactionManager::follow_contents(oop obj) { diff --git a/src/hotspot/share/gc/parallel/psMarkSweep.cpp b/src/hotspot/share/gc/parallel/psMarkSweep.cpp index 76f0d444f6f..db566bf0ad0 100644 --- a/src/hotspot/share/gc/parallel/psMarkSweep.cpp +++ b/src/hotspot/share/gc/parallel/psMarkSweep.cpp @@ -47,6 +47,7 @@ #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/spaceDecorator.hpp" +#include "gc/shared/weakProcessor.hpp" #include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/biasedLocking.hpp" @@ -173,7 +174,9 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(true /* Full GC */,gc_cause); - if (TraceOldGenTime) accumulated_time()->start(); + if (log_is_enabled(Debug, gc, heap, exit)) { + accumulated_time()->start(); + } // Let the size policy know we're starting size_policy->major_collection_begin(); @@ -342,7 +345,9 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { // We collected the heap, recalculate the metaspace capacity MetaspaceGC::compute_new_size(); - if (TraceOldGenTime) accumulated_time()->stop(); + if (log_is_enabled(Debug, gc, heap, exit)) { + accumulated_time()->stop(); + } young_gen->print_used_change(young_gen_prev_used); old_gen->print_used_change(old_gen_prev_used); @@ -541,6 +546,11 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // This is the point where the entire marking should have completed. assert(_marking_stack.is_empty(), "Marking should have completed"); + { + GCTraceTime(Debug, gc, phases) t("Weak Processing", _gc_timer); + WeakProcessor::weak_oops_do(is_alive_closure(), &do_nothing_cl); + } + { GCTraceTime(Debug, gc, phases) t("Class Unloading", _gc_timer); @@ -613,7 +623,7 @@ void PSMarkSweep::mark_sweep_phase3() { // Now adjust pointers in remaining weak roots. (All of which should // have been cleared if they pointed to non-surviving objects.) // Global (weak) JNI handles - JNIHandles::weak_oops_do(adjust_pointer_closure()); + WeakProcessor::oops_do(adjust_pointer_closure()); CodeBlobToOopClosure adjust_from_blobs(adjust_pointer_closure(), CodeBlobToOopClosure::FixRelocations); CodeCache::blobs_do(&adjust_from_blobs); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index ae04316cb3e..9fea2221bfc 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -52,6 +52,7 @@ #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/spaceDecorator.hpp" +#include "gc/shared/weakProcessor.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.inline.hpp" @@ -520,8 +521,8 @@ void ParallelCompactData::add_obj(HeapWord* addr, size_t len) const size_t beg_region = obj_ofs >> Log2RegionSize; const size_t end_region = (obj_ofs + len - 1) >> Log2RegionSize; - DEBUG_ONLY(Atomic::inc_ptr(&add_obj_count);) - DEBUG_ONLY(Atomic::add_ptr(len, &add_obj_size);) + DEBUG_ONLY(Atomic::inc(&add_obj_count);) + DEBUG_ONLY(Atomic::add(len, &add_obj_size);) if (beg_region == end_region) { // All in one region. @@ -838,11 +839,6 @@ PSParallelCompact::IsAliveClosure PSParallelCompact::_is_alive_closure; bool PSParallelCompact::IsAliveClosure::do_object_b(oop p) { return mark_bitmap()->is_marked(p); } -void PSParallelCompact::AdjustKlassClosure::do_klass(Klass* klass) { - PSParallelCompact::AdjustPointerClosure closure(_cm); - klass->oops_do(&closure); -} - void PSParallelCompact::post_initialize() { ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); MemRegion mr = heap->reserved_region(); @@ -1778,7 +1774,9 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(true /* Full GC */,gc_cause); - if (TraceOldGenTime) accumulated_time()->start(); + if (log_is_enabled(Debug, gc, heap, exit)) { + accumulated_time()->start(); + } // Let the size policy know we're starting size_policy->major_collection_begin(); @@ -1897,7 +1895,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { // Resize the metaspace capacity after a collection MetaspaceGC::compute_new_size(); - if (TraceOldGenTime) { + if (log_is_enabled(Debug, gc, heap, exit)) { accumulated_time()->stop(); } @@ -2124,6 +2122,11 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, // This is the point where the entire marking should have completed. assert(cm->marking_stacks_empty(), "Marking should have completed"); + { + GCTraceTime(Debug, gc, phases) tm("Weak Processing", &_gc_timer); + WeakProcessor::weak_oops_do(is_alive_closure(), &do_nothing_cl); + } + { GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", &_gc_timer); @@ -2160,7 +2163,6 @@ void PSParallelCompact::adjust_roots(ParCompactionManager* cm) { ClassLoaderDataGraph::clear_claimed_marks(); PSParallelCompact::AdjustPointerClosure oop_closure(cm); - PSParallelCompact::AdjustKlassClosure klass_closure(cm); // General strong roots. Universe::oops_do(&oop_closure); @@ -2170,12 +2172,11 @@ void PSParallelCompact::adjust_roots(ParCompactionManager* cm) { Management::oops_do(&oop_closure); JvmtiExport::oops_do(&oop_closure); SystemDictionary::oops_do(&oop_closure); - ClassLoaderDataGraph::oops_do(&oop_closure, &klass_closure, true); + ClassLoaderDataGraph::oops_do(&oop_closure, true); // Now adjust pointers in remaining weak roots. (All of which should // have been cleared if they pointed to non-surviving objects.) - // Global (weak) JNI handles - JNIHandles::weak_oops_do(&oop_closure); + WeakProcessor::oops_do(&oop_closure); CodeBlobToOopClosure adjust_from_blobs(&oop_closure, CodeBlobToOopClosure::FixRelocations); CodeCache::blobs_do(&adjust_from_blobs); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 6bf8270d7fd..0060886dc28 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -517,7 +517,7 @@ ParallelCompactData::RegionData::set_blocks_filled() OrderAccess::release(); _blocks_filled = true; // Debug builds count the number of times the table was filled. - DEBUG_ONLY(Atomic::inc_ptr(&_blocks_filled_count)); + DEBUG_ONLY(Atomic::inc(&_blocks_filled_count)); } inline void @@ -586,7 +586,7 @@ inline void ParallelCompactData::RegionData::set_highest_ref(HeapWord* addr) #ifdef ASSERT HeapWord* tmp = _highest_ref; while (addr > tmp) { - tmp = (HeapWord*)Atomic::cmpxchg_ptr(addr, &_highest_ref, tmp); + tmp = Atomic::cmpxchg(addr, &_highest_ref, tmp); } #endif // #ifdef ASSERT } diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index db50e7bcf7b..3cf3e2302a0 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -45,6 +45,7 @@ #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/spaceDecorator.hpp" +#include "gc/shared/weakProcessor.hpp" #include "memory/resourceArea.hpp" #include "logging/log.hpp" #include "oops/oop.inline.hpp" @@ -306,7 +307,9 @@ bool PSScavenge::invoke_no_policy() { TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(false /* not full GC */,gc_cause); - if (TraceYoungGenTime) accumulated_time()->start(); + if (log_is_enabled(Debug, gc, heap, exit)) { + accumulated_time()->start(); + } // Let the size policy know we're starting size_policy->minor_collection_begin(); @@ -438,13 +441,24 @@ bool PSScavenge::invoke_no_policy() { pt.print_enqueue_phase(); } + assert(promotion_manager->stacks_empty(),"stacks should be empty at this point"); + + PSScavengeRootsClosure root_closure(promotion_manager); + + { + GCTraceTime(Debug, gc, phases) tm("Weak Processing", &_gc_timer); + WeakProcessor::weak_oops_do(&_is_alive_closure, &root_closure); + } + { GCTraceTime(Debug, gc, phases) tm("Scrub String Table", &_gc_timer); // Unlink any dead interned Strings and process the remaining live ones. - PSScavengeRootsClosure root_closure(promotion_manager); StringTable::unlink_or_oops_do(&_is_alive_closure, &root_closure); } + // Verify that usage of root_closure didn't copy any objects. + assert(promotion_manager->stacks_empty(),"stacks should be empty at this point"); + // Finally, flush the promotion_manager's labs, and deallocate its stacks. promotion_failure_occurred = PSPromotionManager::post_scavenge(_gc_tracer); if (promotion_failure_occurred) { @@ -607,7 +621,9 @@ bool PSScavenge::invoke_no_policy() { CardTableExtension::verify_all_young_refs_imprecise(); } - if (TraceYoungGenTime) accumulated_time()->stop(); + if (log_is_enabled(Debug, gc, heap, exit)) { + accumulated_time()->stop(); + } young_gen->print_used_change(pre_gc_values.young_gen_used()); old_gen->print_used_change(pre_gc_values.old_gen_used()); diff --git a/src/hotspot/share/gc/parallel/psScavenge.inline.hpp b/src/hotspot/share/gc/parallel/psScavenge.inline.hpp index a944277d00f..70bb4ba4afc 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.inline.hpp +++ b/src/hotspot/share/gc/parallel/psScavenge.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2017, 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 @@ -85,15 +85,15 @@ class PSRootsClosure: public OopClosure { typedef PSRootsClosure PSScavengeRootsClosure; typedef PSRootsClosure PSPromoteRootsClosure; -// Scavenges a single oop in a Klass. -class PSScavengeFromKlassClosure: public OopClosure { +// Scavenges a single oop in a ClassLoaderData. +class PSScavengeFromCLDClosure: public OopClosure { private: PSPromotionManager* _pm; - // Used to redirty a scanned klass if it has oops + // Used to redirty a scanned cld if it has oops // pointing to the young generation after being scanned. - Klass* _scanned_klass; + ClassLoaderData* _scanned_cld; public: - PSScavengeFromKlassClosure(PSPromotionManager* pm) : _pm(pm), _scanned_klass(NULL) { } + PSScavengeFromCLDClosure(PSPromotionManager* pm) : _pm(pm), _scanned_cld(NULL) { } void do_oop(narrowOop* p) { ShouldNotReachHere(); } void do_oop(oop* p) { ParallelScavengeHeap* psh = ParallelScavengeHeap::heap(); @@ -111,48 +111,46 @@ class PSScavengeFromKlassClosure: public OopClosure { oopDesc::encode_store_heap_oop_not_null(p, new_obj); if (PSScavenge::is_obj_in_young(new_obj)) { - do_klass_barrier(); + do_cld_barrier(); } } } - void set_scanned_klass(Klass* klass) { - assert(_scanned_klass == NULL || klass == NULL, "Should always only handling one klass at a time"); - _scanned_klass = klass; + void set_scanned_cld(ClassLoaderData* cld) { + assert(_scanned_cld == NULL || cld == NULL, "Should always only handling one cld at a time"); + _scanned_cld = cld; } private: - void do_klass_barrier() { - assert(_scanned_klass != NULL, "Should not be called without having a scanned klass"); - _scanned_klass->record_modified_oops(); + void do_cld_barrier() { + assert(_scanned_cld != NULL, "Should not be called without having a scanned cld"); + _scanned_cld->record_modified_oops(); } - }; -// Scavenges the oop in a Klass. -class PSScavengeKlassClosure: public KlassClosure { +// Scavenges the oop in a ClassLoaderData. +class PSScavengeCLDClosure: public CLDClosure { private: - PSScavengeFromKlassClosure _oop_closure; + PSScavengeFromCLDClosure _oop_closure; protected: public: - PSScavengeKlassClosure(PSPromotionManager* pm) : _oop_closure(pm) { } - void do_klass(Klass* klass) { - // If the klass has not been dirtied we know that there's + PSScavengeCLDClosure(PSPromotionManager* pm) : _oop_closure(pm) { } + void do_cld(ClassLoaderData* cld) { + // If the cld has not been dirtied we know that there's // no references into the young gen and we can skip it. - if (klass->has_modified_oops()) { - // Clean the klass since we're going to scavenge all the metadata. - klass->clear_modified_oops(); - - // Setup the promotion manager to redirty this klass + if (cld->has_modified_oops()) { + // Setup the promotion manager to redirty this cld // if references are left in the young gen. - _oop_closure.set_scanned_klass(klass); + _oop_closure.set_scanned_cld(cld); - klass->oops_do(&_oop_closure); + // Clean the cld since we're going to scavenge all the metadata. + cld->oops_do(&_oop_closure, false, /*clear_modified_oops*/true); - _oop_closure.set_scanned_klass(NULL); + _oop_closure.set_scanned_cld(NULL); } } }; + #endif // SHARE_VM_GC_PARALLEL_PSSCAVENGE_INLINE_HPP diff --git a/src/hotspot/share/gc/parallel/psTasks.cpp b/src/hotspot/share/gc/parallel/psTasks.cpp index 35e63dc52c3..3effcc6d1f6 100644 --- a/src/hotspot/share/gc/parallel/psTasks.cpp +++ b/src/hotspot/share/gc/parallel/psTasks.cpp @@ -79,8 +79,8 @@ void ScavengeRootsTask::do_it(GCTaskManager* manager, uint which) { case class_loader_data: { - PSScavengeKlassClosure klass_closure(pm); - ClassLoaderDataGraph::oops_do(&roots_closure, &klass_closure, false); + PSScavengeCLDClosure cld_closure(pm); + ClassLoaderDataGraph::cld_do(&cld_closure); } break; diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index db6977aa362..f6bf3437f3e 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -41,6 +41,7 @@ #include "gc/shared/space.inline.hpp" #include "gc/shared/spaceDecorator.hpp" #include "gc/shared/strongRootsScope.hpp" +#include "gc/shared/weakProcessor.hpp" #include "logging/log.hpp" #include "memory/iterator.hpp" #include "memory/resourceArea.hpp" @@ -121,7 +122,7 @@ void DefNewGeneration::FastEvacuateFollowersClosure::do_void() { } ScanClosure::ScanClosure(DefNewGeneration* g, bool gc_barrier) : - OopsInKlassOrGenClosure(g), _g(g), _gc_barrier(gc_barrier) + OopsInClassLoaderDataOrGenClosure(g), _g(g), _gc_barrier(gc_barrier) { _boundary = _g->reserved().end(); } @@ -130,7 +131,7 @@ void ScanClosure::do_oop(oop* p) { ScanClosure::do_oop_work(p); } void ScanClosure::do_oop(narrowOop* p) { ScanClosure::do_oop_work(p); } FastScanClosure::FastScanClosure(DefNewGeneration* g, bool gc_barrier) : - OopsInKlassOrGenClosure(g), _g(g), _gc_barrier(gc_barrier) + OopsInClassLoaderDataOrGenClosure(g), _g(g), _gc_barrier(gc_barrier) { _boundary = _g->reserved().end(); } @@ -138,30 +139,28 @@ FastScanClosure::FastScanClosure(DefNewGeneration* g, bool gc_barrier) : void FastScanClosure::do_oop(oop* p) { FastScanClosure::do_oop_work(p); } void FastScanClosure::do_oop(narrowOop* p) { FastScanClosure::do_oop_work(p); } -void KlassScanClosure::do_klass(Klass* klass) { +void CLDScanClosure::do_cld(ClassLoaderData* cld) { NOT_PRODUCT(ResourceMark rm); - log_develop_trace(gc, scavenge)("KlassScanClosure::do_klass " PTR_FORMAT ", %s, dirty: %s", - p2i(klass), - klass->external_name(), - klass->has_modified_oops() ? "true" : "false"); + log_develop_trace(gc, scavenge)("CLDScanClosure::do_cld " PTR_FORMAT ", %s, dirty: %s", + p2i(cld), + cld->loader_name(), + cld->has_modified_oops() ? "true" : "false"); - // If the klass has not been dirtied we know that there's + // If the cld has not been dirtied we know that there's // no references into the young gen and we can skip it. - if (klass->has_modified_oops()) { + if (cld->has_modified_oops()) { if (_accumulate_modified_oops) { - klass->accumulate_modified_oops(); + cld->accumulate_modified_oops(); } - // Clear this state since we're going to scavenge all the metadata. - klass->clear_modified_oops(); - - // Tell the closure which Klass is being scanned so that it can be dirtied + // Tell the closure which CLD is being scanned so that it can be dirtied // if oops are left pointing into the young gen. - _scavenge_closure->set_scanned_klass(klass); + _scavenge_closure->set_scanned_cld(cld); - klass->oops_do(_scavenge_closure); + // Clean the cld since we're going to scavenge all the metadata. + cld->oops_do(_scavenge_closure, false, /*clear_modified_oops*/true); - _scavenge_closure->set_scanned_klass(NULL); + _scavenge_closure->set_scanned_cld(NULL); } } @@ -177,12 +176,6 @@ void ScanWeakRefClosure::do_oop(narrowOop* p) { ScanWeakRefClosure::do_oop_work( void FilteringClosure::do_oop(oop* p) { FilteringClosure::do_oop_work(p); } void FilteringClosure::do_oop(narrowOop* p) { FilteringClosure::do_oop_work(p); } -KlassScanClosure::KlassScanClosure(OopsInKlassOrGenClosure* scavenge_closure, - KlassRemSet* klass_rem_set) - : _scavenge_closure(scavenge_closure), - _accumulate_modified_oops(klass_rem_set->accumulate_modified_oops()) {} - - DefNewGeneration::DefNewGeneration(ReservedSpace rs, size_t initial_size, const char* policy) @@ -629,11 +622,8 @@ void DefNewGeneration::collect(bool full, FastScanClosure fsc_with_no_gc_barrier(this, false); FastScanClosure fsc_with_gc_barrier(this, true); - KlassScanClosure klass_scan_closure(&fsc_with_no_gc_barrier, - gch->rem_set()->klass_rem_set()); - CLDToKlassAndOopClosure cld_scan_closure(&klass_scan_closure, - &fsc_with_no_gc_barrier, - false); + CLDScanClosure cld_scan_closure(&fsc_with_no_gc_barrier, + gch->rem_set()->cld_rem_set()->accumulate_modified_oops()); set_promo_failure_scan_stack_closure(&fsc_with_no_gc_barrier); FastEvacuateFollowersClosure evacuate_followers(gch, @@ -669,6 +659,13 @@ void DefNewGeneration::collect(bool full, gc_tracer.report_tenuring_threshold(tenuring_threshold()); pt.print_all_references(); + assert(gch->no_allocs_since_save_marks(), "save marks have not been newly set."); + + WeakProcessor::weak_oops_do(&is_alive, &keep_alive); + + // Verify that the usage of keep_alive didn't copy any objects. + assert(gch->no_allocs_since_save_marks(), "save marks have not been newly set."); + if (!_promotion_failed) { // Swap the survivor spaces. eden()->clear(SpaceDecorator::Mangle); @@ -745,8 +742,11 @@ void DefNewGeneration::remove_forwarding_pointers() { RemoveForwardedPointerClosure rspc; eden()->object_iterate(&rspc); from()->object_iterate(&rspc); + restore_preserved_marks(); +} - SharedRestorePreservedMarksTaskExecutor task_executor(GenCollectedHeap::heap()->workers()); +void DefNewGeneration::restore_preserved_marks() { + SharedRestorePreservedMarksTaskExecutor task_executor(NULL); _preserved_marks_set.restore(&task_executor); } diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index e2ff971ddda..19ca2ac4707 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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 @@ -89,6 +89,8 @@ protected: // therefore we must remove their forwarding pointers. void remove_forwarding_pointers(); + virtual void restore_preserved_marks(); + // Preserved marks PreservedMarksSet _preserved_marks_set; diff --git a/src/hotspot/share/gc/serial/genMarkSweep.cpp b/src/hotspot/share/gc/serial/genMarkSweep.cpp index e7c58edf722..8f22aea7a19 100644 --- a/src/hotspot/share/gc/serial/genMarkSweep.cpp +++ b/src/hotspot/share/gc/serial/genMarkSweep.cpp @@ -43,6 +43,7 @@ #include "gc/shared/referencePolicy.hpp" #include "gc/shared/space.hpp" #include "gc/shared/strongRootsScope.hpp" +#include "gc/shared/weakProcessor.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" @@ -220,6 +221,11 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // This is the point where the entire marking should have completed. assert(_marking_stack.is_empty(), "Marking should have completed"); + { + GCTraceTime(Debug, gc, phases) tm_m("Weak Processing", gc_timer()); + WeakProcessor::weak_oops_do(&is_alive, &do_nothing_cl); + } + { GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", gc_timer()); diff --git a/src/hotspot/share/gc/shared/barrierSet.hpp b/src/hotspot/share/gc/shared/barrierSet.hpp index 39ce1161127..eaec4af4fcc 100644 --- a/src/hotspot/share/gc/shared/barrierSet.hpp +++ b/src/hotspot/share/gc/shared/barrierSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -80,50 +80,11 @@ public: // End of fake RTTI support. -public: - enum Flags { - None = 0, - TargetUninitialized = 1 - }; - protected: - // Some barrier sets create tables whose elements correspond to parts of - // the heap; the CardTableModRefBS is an example. Such barrier sets will - // normally reserve space for such tables, and commit parts of the table - // "covering" parts of the heap that are committed. At most one covered - // region per generation is needed. - static const int _max_covered_regions = 2; - BarrierSet(const FakeRtti& fake_rtti) : _fake_rtti(fake_rtti) { } ~BarrierSet() { } public: - - // These operations indicate what kind of barriers the BarrierSet has. - virtual bool has_read_ref_barrier() = 0; - virtual bool has_read_prim_barrier() = 0; - virtual bool has_write_ref_barrier() = 0; - virtual bool has_write_ref_pre_barrier() = 0; - virtual bool has_write_prim_barrier() = 0; - - // These functions indicate whether a particular access of the given - // kinds requires a barrier. - virtual bool read_ref_needs_barrier(void* field) = 0; - virtual bool read_prim_needs_barrier(HeapWord* field, size_t bytes) = 0; - virtual bool write_prim_needs_barrier(HeapWord* field, size_t bytes, - juint val1, juint val2) = 0; - - // The first four operations provide a direct implementation of the - // barrier set. An interpreter loop, for example, could call these - // directly, as appropriate. - - // Invoke the barrier, if any, necessary when reading the given ref field. - virtual void read_ref_field(void* field) = 0; - - // Invoke the barrier, if any, necessary when reading the given primitive - // "field" of "bytes" bytes in "obj". - virtual void read_prim_field(HeapWord* field, size_t bytes) = 0; - // Invoke the barrier, if any, necessary when writing "new_val" into the // ref field at "offset" in "obj". // (For efficiency reasons, this operation is specialized for certain @@ -131,48 +92,19 @@ public: // virtual "_work" function below, which must implement the barrier.) // First the pre-write versions... template inline void write_ref_field_pre(T* field, oop new_val); -private: - // Helper for write_ref_field_pre and friends, testing for specialized cases. - bool devirtualize_reference_writes() const; - - // Keep this private so as to catch violations at build time. - virtual void write_ref_field_pre_work( void* field, oop new_val) { guarantee(false, "Not needed"); }; -protected: - virtual void write_ref_field_pre_work( oop* field, oop new_val) {}; - virtual void write_ref_field_pre_work(narrowOop* field, oop new_val) {}; -public: // ...then the post-write version. inline void write_ref_field(void* field, oop new_val, bool release = false); + protected: + virtual void write_ref_field_pre_work( oop* field, oop new_val) {}; + virtual void write_ref_field_pre_work(narrowOop* field, oop new_val) {}; virtual void write_ref_field_work(void* field, oop new_val, bool release) = 0; + public: - - // Invoke the barrier, if any, necessary when writing the "bytes"-byte - // value(s) "val1" (and "val2") into the primitive "field". - virtual void write_prim_field(HeapWord* field, size_t bytes, - juint val1, juint val2) = 0; - // Operations on arrays, or general regions (e.g., for "clone") may be // optimized by some barriers. - // The first six operations tell whether such an optimization exists for - // the particular barrier. - virtual bool has_read_ref_array_opt() = 0; - virtual bool has_read_prim_array_opt() = 0; - virtual bool has_write_ref_array_pre_opt() { return true; } - virtual bool has_write_ref_array_opt() = 0; - virtual bool has_write_prim_array_opt() = 0; - - virtual bool has_read_region_opt() = 0; - virtual bool has_write_region_opt() = 0; - - // These operations should assert false unless the corresponding operation - // above returns true. Otherwise, they should perform an appropriate - // barrier for an array whose elements are all in the given memory region. - virtual void read_ref_array(MemRegion mr) = 0; - virtual void read_prim_array(MemRegion mr) = 0; - // Below length is the # array elements being written virtual void write_ref_array_pre(oop* dst, int length, bool dest_uninitialized = false) {} @@ -193,17 +125,16 @@ public: protected: virtual void write_ref_array_work(MemRegion mr) = 0; + public: - virtual void write_prim_array(MemRegion mr) = 0; - - virtual void read_region(MemRegion mr) = 0; - // (For efficiency reasons, this operation is specialized for certain // barrier types. Semantically, it should be thought of as a call to the // virtual "_work" function below, which must implement the barrier.) void write_region(MemRegion mr); + protected: virtual void write_region_work(MemRegion mr) = 0; + public: // Inform the BarrierSet that the the covered heap region that starts // with "base" has been changed to have the given size (possibly from 0, diff --git a/src/hotspot/share/gc/shared/barrierSet.inline.hpp b/src/hotspot/share/gc/shared/barrierSet.inline.hpp index d8ffd4da8e5..56b567a87d5 100644 --- a/src/hotspot/share/gc/shared/barrierSet.inline.hpp +++ b/src/hotspot/share/gc/shared/barrierSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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,37 +26,15 @@ #define SHARE_VM_GC_SHARED_BARRIERSET_INLINE_HPP #include "gc/shared/barrierSet.hpp" -#include "gc/shared/cardTableModRefBS.inline.hpp" #include "utilities/align.hpp" -// Inline functions of BarrierSet, which de-virtualize certain -// performance-critical calls when the barrier is the most common -// card-table kind. - -inline bool BarrierSet::devirtualize_reference_writes() const { - switch (kind()) { - case CardTableForRS: - case CardTableExtension: - return true; - default: - return false; - } -} template void BarrierSet::write_ref_field_pre(T* field, oop new_val) { - if (devirtualize_reference_writes()) { - barrier_set_cast(this)->inline_write_ref_field_pre(field, new_val); - } else { - write_ref_field_pre_work(field, new_val); - } + write_ref_field_pre_work(field, new_val); } void BarrierSet::write_ref_field(void* field, oop new_val, bool release) { - if (devirtualize_reference_writes()) { - barrier_set_cast(this)->inline_write_ref_field(field, new_val, release); - } else { - write_ref_field_work(field, new_val, release); - } + write_ref_field_work(field, new_val, release); } // count is number of array elements being written @@ -84,11 +62,7 @@ void BarrierSet::write_ref_array(HeapWord* start, size_t count) { inline void BarrierSet::write_region(MemRegion mr) { - if (devirtualize_reference_writes()) { - barrier_set_cast(this)->inline_write_region(mr); - } else { - write_region_work(mr); - } + write_region_work(mr); } #endif // SHARE_VM_GC_SHARED_BARRIERSET_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/cardTableModRefBS.hpp b/src/hotspot/share/gc/shared/cardTableModRefBS.hpp index 80d9cb8b072..5254bfeb6f3 100644 --- a/src/hotspot/share/gc/shared/cardTableModRefBS.hpp +++ b/src/hotspot/share/gc/shared/cardTableModRefBS.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -73,7 +73,15 @@ class CardTableModRefBS: public ModRefBarrierSet { size_t _byte_map_size; // in bytes jbyte* _byte_map; // the card marking array + // Some barrier sets create tables whose elements correspond to parts of + // the heap; the CardTableModRefBS is an example. Such barrier sets will + // normally reserve space for such tables, and commit parts of the table + // "covering" parts of the heap that are committed. At most one covered + // region per generation is needed. + static const int _max_covered_regions = 2; + int _cur_covered_regions; + // The covered regions should be in address order. MemRegion* _covered; // The committed regions correspond one-to-one to the covered regions. @@ -89,7 +97,6 @@ class CardTableModRefBS: public ModRefBarrierSet { // uncommit the MemRegion for that page. MemRegion _guard_region; - protected: inline size_t compute_byte_map_size(); // Finds and return the index of the region, if any, to which the given @@ -135,7 +142,6 @@ class CardTableModRefBS: public ModRefBarrierSet { return byte_for(p) + 1; } - protected: // Dirty the bytes corresponding to "mr" (not all of which must be // covered.) void dirty_MemRegion(MemRegion mr); @@ -144,7 +150,7 @@ class CardTableModRefBS: public ModRefBarrierSet { // all of which must be covered.) void clear_MemRegion(MemRegion mr); -public: + public: // Constants enum SomePublicConstants { card_shift = 9, @@ -163,8 +169,6 @@ public: // *** Barrier set functions. - bool has_write_ref_pre_barrier() { return false; } - // Initialization utilities; covered_words is the size of the covered region // in, um, words. inline size_t cards_required(size_t covered_words) { @@ -173,8 +177,7 @@ public: return words / card_size_in_words + 1; } -protected: - + protected: CardTableModRefBS(MemRegion whole_heap, const BarrierSet::FakeRtti& fake_rtti); ~CardTableModRefBS(); @@ -185,29 +188,18 @@ protected: void write_ref_field_work(oop obj, size_t offset, oop newVal); virtual void write_ref_field_work(void* field, oop newVal, bool release); -public: - bool has_write_ref_array_opt() { return true; } - bool has_write_region_opt() { return true; } - - inline void inline_write_region(MemRegion mr) { - dirty_MemRegion(mr); - } -protected: + protected: void write_region_work(MemRegion mr) { - inline_write_region(mr); - } -public: - - inline void inline_write_ref_array(MemRegion mr) { dirty_MemRegion(mr); } -protected: - void write_ref_array_work(MemRegion mr) { - inline_write_ref_array(mr); - } -public: + protected: + void write_ref_array_work(MemRegion mr) { + dirty_MemRegion(mr); + } + + public: bool is_aligned(HeapWord* addr) { return is_card_aligned(addr); } diff --git a/src/hotspot/share/gc/shared/cardTableModRefBS.inline.hpp b/src/hotspot/share/gc/shared/cardTableModRefBS.inline.hpp index 7b01a379558..bce8661cf86 100644 --- a/src/hotspot/share/gc/shared/cardTableModRefBS.inline.hpp +++ b/src/hotspot/share/gc/shared/cardTableModRefBS.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -30,10 +30,10 @@ #include "runtime/orderAccess.inline.hpp" template inline void CardTableModRefBS::inline_write_ref_field(T* field, oop newVal, bool release) { - jbyte* byte = byte_for((void*)field); + volatile jbyte* byte = byte_for((void*)field); if (release) { // Perform a releasing store if requested. - OrderAccess::release_store((volatile jbyte*) byte, dirty_card); + OrderAccess::release_store(byte, jbyte(dirty_card)); } else { *byte = dirty_card; } diff --git a/src/hotspot/share/gc/shared/cardTableRS.cpp b/src/hotspot/share/gc/shared/cardTableRS.cpp index 0c87676ce02..27d015110c4 100644 --- a/src/hotspot/share/gc/shared/cardTableRS.cpp +++ b/src/hotspot/share/gc/shared/cardTableRS.cpp @@ -34,16 +34,16 @@ #include "runtime/os.hpp" #include "utilities/macros.hpp" -class HasAccumulatedModifiedOopsClosure : public KlassClosure { +class HasAccumulatedModifiedOopsClosure : public CLDClosure { bool _found; public: HasAccumulatedModifiedOopsClosure() : _found(false) {} - void do_klass(Klass* klass) { + void do_cld(ClassLoaderData* cld) { if (_found) { return; } - if (klass->has_accumulated_modified_oops()) { + if (cld->has_accumulated_modified_oops()) { _found = true; } } @@ -52,28 +52,29 @@ class HasAccumulatedModifiedOopsClosure : public KlassClosure { } }; -bool KlassRemSet::mod_union_is_clear() { +bool CLDRemSet::mod_union_is_clear() { HasAccumulatedModifiedOopsClosure closure; - ClassLoaderDataGraph::classes_do(&closure); + ClassLoaderDataGraph::cld_do(&closure); return !closure.found(); } -class ClearKlassModUnionClosure : public KlassClosure { +class ClearCLDModUnionClosure : public CLDClosure { public: - void do_klass(Klass* klass) { - if (klass->has_accumulated_modified_oops()) { - klass->clear_accumulated_modified_oops(); + void do_cld(ClassLoaderData* cld) { + if (cld->has_accumulated_modified_oops()) { + cld->clear_accumulated_modified_oops(); } } }; -void KlassRemSet::clear_mod_union() { - ClearKlassModUnionClosure closure; - ClassLoaderDataGraph::classes_do(&closure); +void CLDRemSet::clear_mod_union() { + ClearCLDModUnionClosure closure; + ClassLoaderDataGraph::cld_do(&closure); } + CardTableRS::CardTableRS(MemRegion whole_heap) : _bs(NULL), _cur_youngergen_card_val(youngergenP1_card) diff --git a/src/hotspot/share/gc/shared/cardTableRS.hpp b/src/hotspot/share/gc/shared/cardTableRS.hpp index 5139580b61f..5713f04b5ce 100644 --- a/src/hotspot/share/gc/shared/cardTableRS.hpp +++ b/src/hotspot/share/gc/shared/cardTableRS.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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 @@ -31,11 +31,11 @@ class Space; class OopsInGenClosure; -// Helper to remember modified oops in all klasses. -class KlassRemSet { +// Helper to remember modified oops in all clds. +class CLDRemSet { bool _accumulate_modified_oops; public: - KlassRemSet() : _accumulate_modified_oops(false) {} + CLDRemSet() : _accumulate_modified_oops(false) {} void set_accumulate_modified_oops(bool value) { _accumulate_modified_oops = value; } bool accumulate_modified_oops() { return _accumulate_modified_oops; } bool mod_union_is_clear(); @@ -64,7 +64,7 @@ class CardTableRS: public CHeapObj { return CardTableModRefBSForCTRS::card_is_dirty_wrt_gen_iter(cv); } - KlassRemSet _klass_rem_set; + CLDRemSet _cld_rem_set; BarrierSet* _bs; CardTableModRefBSForCTRS* _ct_bs; @@ -121,7 +121,7 @@ public: // Set the barrier set. void set_bs(BarrierSet* bs) { _bs = bs; } - KlassRemSet* klass_rem_set() { return &_klass_rem_set; } + CLDRemSet* cld_rem_set() { return &_cld_rem_set; } CardTableModRefBSForCTRS* ct_bs() { return _ct_bs; } diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index deb9da3cbd8..b97ae63ca19 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -135,14 +135,6 @@ void CollectedHeap::print_on_error(outputStream* st) const { _barrier_set->print_on(st); } -void CollectedHeap::register_nmethod(nmethod* nm) { - assert_locked_or_safepoint(CodeCache_lock); -} - -void CollectedHeap::unregister_nmethod(nmethod* nm) { - assert_locked_or_safepoint(CodeCache_lock); -} - void CollectedHeap::trace_heap(GCWhen::Type when, const GCTracer* gc_tracer) { const GCHeapSummary& heap_summary = create_heap_summary(); gc_tracer->report_gc_heap_summary(when, heap_summary); @@ -355,7 +347,6 @@ void CollectedHeap::flush_deferred_store_barrier(JavaThread* thread) { "Mismatch: multiple objects?"); } BarrierSet* bs = barrier_set(); - assert(bs->has_write_region_opt(), "No write_region() on BarrierSet"); bs->write_region(deferred); // "Clear" the deferred_card_mark field thread->set_deferred_card_mark(MemRegion()); @@ -438,7 +429,6 @@ oop CollectedHeap::new_store_pre_barrier(JavaThread* thread, oop new_obj) { } else { // Do the card mark BarrierSet* bs = barrier_set(); - assert(bs->has_write_region_opt(), "No write_region() on BarrierSet"); bs->write_region(mr); } } diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index 10b9fb302e2..740f50282b3 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -83,6 +83,7 @@ class GCHeapLog : public EventLogBase { // GenCollectedHeap // G1CollectedHeap // ParallelScavengeHeap +// CMSHeap // class CollectedHeap : public CHeapObj { friend class VMStructs; @@ -194,7 +195,8 @@ class CollectedHeap : public CHeapObj { enum Name { GenCollectedHeap, ParallelScavengeHeap, - G1CollectedHeap + G1CollectedHeap, + CMSHeap }; static inline size_t filler_array_max_size() { @@ -219,6 +221,10 @@ class CollectedHeap : public CHeapObj { // Stop any onging concurrent work and prepare for exit. virtual void stop() {} + // Stop and resume concurrent GC threads interfering with safepoint operations + virtual void safepoint_synchronize_begin() {} + virtual void safepoint_synchronize_end() {} + void initialize_reserved_region(HeapWord *start, HeapWord *end); MemRegion reserved_region() const { return _reserved; } address base() const { return (address)reserved_region().start(); } @@ -287,10 +293,6 @@ class CollectedHeap : public CHeapObj { return p == NULL || is_in_closed_subset(p); } - // An object is scavengable if its location may move during a scavenge. - // (A scavenge is a GC which is not a full GC.) - virtual bool is_scavengable(const void *p) = 0; - void set_gc_cause(GCCause::Cause v) { if (UsePerfData) { _gc_lastcause = _gc_cause; @@ -568,10 +570,14 @@ class CollectedHeap : public CHeapObj { void print_heap_before_gc(); void print_heap_after_gc(); + // An object is scavengable if its location may move during a scavenge. + // (A scavenge is a GC which is not a full GC.) + virtual bool is_scavengable(oop obj) = 0; // Registering and unregistering an nmethod (compiled code) with the heap. // Override with specific mechanism for each specialized heap type. - virtual void register_nmethod(nmethod* nm); - virtual void unregister_nmethod(nmethod* nm); + virtual void register_nmethod(nmethod* nm) {} + virtual void unregister_nmethod(nmethod* nm) {} + virtual void verify_nmethod(nmethod* nmethod) {} void trace_heap_before_gc(const GCTracer* gc_tracer); void trace_heap_after_gc(const GCTracer* gc_tracer); diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp index eb98e3f2595..d6624936a4a 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp @@ -42,6 +42,7 @@ #include "gc/shared/space.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/vmGCOperations.hpp" +#include "gc/shared/weakProcessor.hpp" #include "gc/shared/workgroup.hpp" #include "memory/filemap.hpp" #include "memory/resourceArea.hpp" @@ -58,28 +59,6 @@ #include "utilities/macros.hpp" #include "utilities/stack.inline.hpp" #include "utilities/vmError.hpp" -#if INCLUDE_ALL_GCS -#include "gc/cms/concurrentMarkSweepThread.hpp" -#include "gc/cms/vmCMSOperations.hpp" -#endif // INCLUDE_ALL_GCS - -NOT_PRODUCT(size_t GenCollectedHeap::_skip_header_HeapWords = 0;) - -// The set of potentially parallel tasks in root scanning. -enum GCH_strong_roots_tasks { - GCH_PS_Universe_oops_do, - GCH_PS_JNIHandles_oops_do, - GCH_PS_ObjectSynchronizer_oops_do, - GCH_PS_Management_oops_do, - GCH_PS_SystemDictionary_oops_do, - GCH_PS_ClassLoaderDataGraph_oops_do, - GCH_PS_jvmti_oops_do, - GCH_PS_CodeCache_oops_do, - GCH_PS_aot_oops_do, - GCH_PS_younger_gens, - // Leave this one last. - GCH_PS_NumElements -}; GenCollectedHeap::GenCollectedHeap(GenCollectorPolicy *policy) : CollectedHeap(), @@ -89,15 +68,6 @@ GenCollectedHeap::GenCollectedHeap(GenCollectorPolicy *policy) : _full_collections_completed(0) { assert(policy != NULL, "Sanity check"); - if (UseConcMarkSweepGC) { - _workers = new WorkGang("GC Thread", ParallelGCThreads, - /* are_GC_task_threads */true, - /* are_ConcurrentGC_threads */false); - _workers->initialize_workers(); - } else { - // Serial GC does not use workers. - _workers = NULL; - } } jint GenCollectedHeap::initialize() { @@ -138,15 +108,6 @@ jint GenCollectedHeap::initialize() { _old_gen = gen_policy()->old_gen_spec()->init(old_rs, rem_set()); clear_incremental_collection_failed(); -#if INCLUDE_ALL_GCS - // If we are running CMS, create the collector responsible - // for collecting the CMS generations. - if (collector_policy()->is_concurrent_mark_sweep_policy()) { - bool success = create_cms_collector(); - if (!success) return JNI_ENOMEM; - } -#endif // INCLUDE_ALL_GCS - return JNI_OK; } @@ -183,21 +144,22 @@ char* GenCollectedHeap::allocate(size_t alignment, void GenCollectedHeap::post_initialize() { ref_processing_init(); - assert((_young_gen->kind() == Generation::DefNew) || - (_young_gen->kind() == Generation::ParNew), - "Wrong youngest generation type"); + check_gen_kinds(); DefNewGeneration* def_new_gen = (DefNewGeneration*)_young_gen; - assert(_old_gen->kind() == Generation::ConcurrentMarkSweep || - _old_gen->kind() == Generation::MarkSweepCompact, - "Wrong generation kind"); - _gen_policy->initialize_size_policy(def_new_gen->eden()->capacity(), _old_gen->capacity(), def_new_gen->from()->capacity()); _gen_policy->initialize_gc_policy_counters(); } +void GenCollectedHeap::check_gen_kinds() { + assert(young_gen()->kind() == Generation::DefNew, + "Wrong youngest generation type"); + assert(old_gen()->kind() == Generation::MarkSweepCompact, + "Wrong generation kind"); +} + void GenCollectedHeap::ref_processing_init() { _young_gen->ref_processor_init(); _old_gen->ref_processor_init(); @@ -309,19 +271,6 @@ bool GenCollectedHeap::must_clear_all_soft_refs() { _gc_cause == GCCause::_wb_full_gc; } -bool GenCollectedHeap::should_do_concurrent_full_gc(GCCause::Cause cause) { - if (!UseConcMarkSweepGC) { - return false; - } - - switch (cause) { - case GCCause::_gc_locker: return GCLockerInvokesConcurrent; - case GCCause::_java_lang_system_gc: - case GCCause::_dcmd_gc_run: return ExplicitGCInvokesConcurrent; - default: return false; - } -} - void GenCollectedHeap::collect_generation(Generation* gen, bool full, size_t size, bool is_tlab, bool run_verification, bool clear_soft_refs, bool restore_marks_for_biased_locking) { @@ -553,6 +502,14 @@ void GenCollectedHeap::do_collection(bool full, #endif } +void GenCollectedHeap::register_nmethod(nmethod* nm) { + CodeCache::register_scavenge_root_nmethod(nm); +} + +void GenCollectedHeap::verify_nmethod(nmethod* nm) { + CodeCache::verify_scavenge_root_nmethod(nm); +} + HeapWord* GenCollectedHeap::satisfy_failed_allocation(size_t size, bool is_tlab) { return gen_policy()->satisfy_failed_allocation(size, is_tlab); } @@ -674,31 +631,6 @@ void GenCollectedHeap::young_process_roots(StrongRootsScope* scope, _process_strong_tasks->all_tasks_completed(scope->n_threads()); } -void GenCollectedHeap::cms_process_roots(StrongRootsScope* scope, - bool young_gen_as_roots, - ScanningOption so, - bool only_strong_roots, - OopsInGenClosure* root_closure, - CLDClosure* cld_closure) { - MarkingCodeBlobClosure mark_code_closure(root_closure, !CodeBlobToOopClosure::FixRelocations); - OopsInGenClosure* weak_roots = only_strong_roots ? NULL : root_closure; - CLDClosure* weak_cld_closure = only_strong_roots ? NULL : cld_closure; - - process_roots(scope, so, root_closure, weak_roots, cld_closure, weak_cld_closure, &mark_code_closure); - if (!only_strong_roots) { - process_string_table_roots(scope, root_closure); - } - - if (young_gen_as_roots && - !_process_strong_tasks->is_task_claimed(GCH_PS_younger_gens)) { - root_closure->set_generation(_young_gen); - _young_gen->oop_iterate(root_closure); - root_closure->reset_generation(); - } - - _process_strong_tasks->all_tasks_completed(scope->n_threads()); -} - void GenCollectedHeap::full_process_roots(StrongRootsScope* scope, bool is_adjust_phase, ScanningOption so, @@ -721,7 +653,7 @@ void GenCollectedHeap::full_process_roots(StrongRootsScope* scope, } void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure) { - JNIHandles::weak_oops_do(root_closure); + WeakProcessor::oops_do(root_closure); _young_gen->ref_processor()->weak_oops_do(root_closure); _old_gen->ref_processor()->weak_oops_do(root_closure); } @@ -763,14 +695,7 @@ HeapWord** GenCollectedHeap::end_addr() const { // public collection interfaces void GenCollectedHeap::collect(GCCause::Cause cause) { - if (should_do_concurrent_full_gc(cause)) { -#if INCLUDE_ALL_GCS - // Mostly concurrent full collection. - collect_mostly_concurrent(cause); -#else // INCLUDE_ALL_GCS - ShouldNotReachHere(); -#endif // INCLUDE_ALL_GCS - } else if (cause == GCCause::_wb_young_gc) { + if (cause == GCCause::_wb_young_gc) { // Young collection for the WhiteBox API. collect(cause, YoungGen); } else { @@ -817,44 +742,6 @@ void GenCollectedHeap::collect_locked(GCCause::Cause cause, GenerationType max_g } } -#if INCLUDE_ALL_GCS -bool GenCollectedHeap::create_cms_collector() { - - assert(_old_gen->kind() == Generation::ConcurrentMarkSweep, - "Unexpected generation kinds"); - // Skip two header words in the block content verification - NOT_PRODUCT(_skip_header_HeapWords = CMSCollector::skip_header_HeapWords();) - assert(_gen_policy->is_concurrent_mark_sweep_policy(), "Unexpected policy type"); - CMSCollector* collector = - new CMSCollector((ConcurrentMarkSweepGeneration*)_old_gen, - _rem_set, - _gen_policy->as_concurrent_mark_sweep_policy()); - - if (collector == NULL || !collector->completed_initialization()) { - if (collector) { - delete collector; // Be nice in embedded situation - } - vm_shutdown_during_initialization("Could not create CMS collector"); - return false; - } - return true; // success -} - -void GenCollectedHeap::collect_mostly_concurrent(GCCause::Cause cause) { - assert(!Heap_lock->owned_by_self(), "Should not own Heap_lock"); - - MutexLocker ml(Heap_lock); - // Read the GC counts while holding the Heap_lock - unsigned int full_gc_count_before = total_full_collections(); - unsigned int gc_count_before = total_collections(); - { - MutexUnlocker mu(Heap_lock); - VM_GenCollectFullConcurrent op(gc_count_before, full_gc_count_before, cause); - VMThread::execute(&op); - } -} -#endif // INCLUDE_ALL_GCS - void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs) { do_full_collection(clear_all_soft_refs, OldGen); } @@ -1097,8 +984,9 @@ void GenCollectedHeap::save_marks() { GenCollectedHeap* GenCollectedHeap::heap() { CollectedHeap* heap = Universe::heap(); assert(heap != NULL, "Uninitialized access to GenCollectedHeap::heap()"); - assert(heap->kind() == CollectedHeap::GenCollectedHeap, "Not a GenCollectedHeap"); - return (GenCollectedHeap*)heap; + assert(heap->kind() == CollectedHeap::GenCollectedHeap || + heap->kind() == CollectedHeap::CMSHeap, "Not a GenCollectedHeap"); + return (GenCollectedHeap*) heap; } void GenCollectedHeap::prepare_for_compaction() { @@ -1126,42 +1014,16 @@ void GenCollectedHeap::print_on(outputStream* st) const { } void GenCollectedHeap::gc_threads_do(ThreadClosure* tc) const { - if (workers() != NULL) { - workers()->threads_do(tc); - } -#if INCLUDE_ALL_GCS - if (UseConcMarkSweepGC) { - ConcurrentMarkSweepThread::threads_do(tc); - } -#endif // INCLUDE_ALL_GCS } void GenCollectedHeap::print_gc_threads_on(outputStream* st) const { -#if INCLUDE_ALL_GCS - if (UseConcMarkSweepGC) { - workers()->print_worker_threads_on(st); - ConcurrentMarkSweepThread::print_all_on(st); - } -#endif // INCLUDE_ALL_GCS -} - -void GenCollectedHeap::print_on_error(outputStream* st) const { - this->CollectedHeap::print_on_error(st); - -#if INCLUDE_ALL_GCS - if (UseConcMarkSweepGC) { - st->cr(); - CMSCollector::print_on_error(st); - } -#endif // INCLUDE_ALL_GCS } void GenCollectedHeap::print_tracing_info() const { - if (TraceYoungGenTime) { - _young_gen->print_summary_info(); - } - if (TraceOldGenTime) { - _old_gen->print_summary_info(); + if (log_is_enabled(Debug, gc, heap, exit)) { + LogStreamHandle(Debug, gc, heap, exit) lsh; + _young_gen->print_summary_info_on(&lsh); + _old_gen->print_summary_info_on(&lsh); } } @@ -1185,7 +1047,6 @@ class GenGCPrologueClosure: public GenCollectedHeap::GenClosure { void GenCollectedHeap::gc_prologue(bool full) { assert(InlineCacheBuffer::is_empty(), "should have cleaned up ICBuffer"); - always_do_update_barrier = false; // Fill TLAB's and such CollectedHeap::accumulate_statistics_all_tlabs(); ensure_parsability(true); // retire TLABs @@ -1223,8 +1084,6 @@ void GenCollectedHeap::gc_epilogue(bool full) { MetaspaceCounters::update_performance_counters(); CompressedClassSpaceCounters::update_performance_counters(); - - always_do_update_barrier = UseConcMarkSweepGC; }; #ifndef PRODUCT @@ -1305,11 +1164,3 @@ jlong GenCollectedHeap::millis_since_last_gc() { } return retVal; } - -void GenCollectedHeap::stop() { -#if INCLUDE_ALL_GCS - if (UseConcMarkSweepGC) { - ConcurrentMarkSweepThread::cmst()->stop(); - } -#endif -} diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.hpp b/src/hotspot/share/gc/shared/genCollectedHeap.hpp index 4d9087341d4..4b51f679623 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.hpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -78,21 +78,34 @@ private: // In support of ExplicitGCInvokesConcurrent functionality unsigned int _full_collections_completed; - // Data structure for claiming the (potentially) parallel tasks in - // (gen-specific) roots processing. - SubTasksDone* _process_strong_tasks; - // Collects the given generation. void collect_generation(Generation* gen, bool full, size_t size, bool is_tlab, bool run_verification, bool clear_soft_refs, bool restore_marks_for_biased_locking); - // In block contents verification, the number of header words to skip - NOT_PRODUCT(static size_t _skip_header_HeapWords;) - - WorkGang* _workers; - protected: + + // The set of potentially parallel tasks in root scanning. + enum GCH_strong_roots_tasks { + GCH_PS_Universe_oops_do, + GCH_PS_JNIHandles_oops_do, + GCH_PS_ObjectSynchronizer_oops_do, + GCH_PS_FlatProfiler_oops_do, + GCH_PS_Management_oops_do, + GCH_PS_SystemDictionary_oops_do, + GCH_PS_ClassLoaderDataGraph_oops_do, + GCH_PS_jvmti_oops_do, + GCH_PS_CodeCache_oops_do, + GCH_PS_aot_oops_do, + GCH_PS_younger_gens, + // Leave this one last. + GCH_PS_NumElements + }; + + // Data structure for claiming the (potentially) parallel tasks in + // (gen-specific) roots processing. + SubTasksDone* _process_strong_tasks; + // Helper functions for allocation HeapWord* attempt_allocation(size_t size, bool is_tlab, @@ -124,8 +137,6 @@ protected: public: GenCollectedHeap(GenCollectorPolicy *policy); - WorkGang* workers() const { return _workers; } - // Returns JNI_OK on success virtual jint initialize(); @@ -135,6 +146,8 @@ public: // Does operations required after initialization has been done. void post_initialize(); + virtual void check_gen_kinds(); + // Initialize ("weak") refs processing support virtual void ref_processing_init(); @@ -143,11 +156,7 @@ public: } virtual const char* name() const { - if (UseConcMarkSweepGC) { - return "Concurrent Mark Sweep"; - } else { - return "Serial"; - } + return "Serial"; } Generation* young_gen() const { return _young_gen; } @@ -190,7 +199,7 @@ public: // Perform a full collection of the heap; intended for use in implementing // "System.gc". This implies as full a collection as the CollectedHeap // supports. Caller does not hold the Heap_lock on entry. - void collect(GCCause::Cause cause); + virtual void collect(GCCause::Cause cause); // The same as above but assume that the caller holds the Heap_lock. void collect_locked(GCCause::Cause cause); @@ -207,12 +216,8 @@ public: bool is_in(const void* p) const; // override - bool is_in_closed_subset(const void* p) const { - if (UseConcMarkSweepGC) { - return is_in_reserved(p); - } else { - return is_in(p); - } + virtual bool is_in_closed_subset(const void* p) const { + return is_in(p); } // Returns true if the reference is to an object in the reserved space @@ -224,10 +229,14 @@ public: bool is_in_partial_collection(const void* p); #endif - virtual bool is_scavengable(const void* addr) { - return is_in_young((oop)addr); + virtual bool is_scavengable(oop obj) { + return is_in_young(obj); } + // Optimized nmethod scanning support routines + virtual void register_nmethod(nmethod* nm); + virtual void verify_nmethod(nmethod* nmethod); + // Iteration functions. void oop_iterate_no_header(OopClosure* cl); void oop_iterate(ExtendedOopClosure* cl); @@ -278,7 +287,7 @@ public: } virtual bool card_mark_must_follow_store() const { - return UseConcMarkSweepGC; + return false; } // We don't need barriers for stores to objects in the @@ -344,7 +353,6 @@ public: virtual void print_gc_threads_on(outputStream* st) const; virtual void gc_threads_do(ThreadClosure* tc) const; virtual void print_tracing_info() const; - virtual void print_on_error(outputStream* st) const; void print_heap_change(size_t young_prev_used, size_t old_prev_used) const; @@ -383,7 +391,7 @@ public: SO_ScavengeCodeCache = 0x10 }; - private: + protected: void process_roots(StrongRootsScope* scope, ScanningOption so, OopClosure* strong_roots, @@ -395,24 +403,20 @@ public: void process_string_table_roots(StrongRootsScope* scope, OopClosure* root_closure); + // Accessor for memory state verification support + NOT_PRODUCT( + virtual size_t skip_header_HeapWords() { return 0; } + ) + + virtual void gc_prologue(bool full); + virtual void gc_epilogue(bool full); + public: void young_process_roots(StrongRootsScope* scope, OopsInGenClosure* root_closure, OopsInGenClosure* old_gen_closure, CLDClosure* cld_closure); - // If "young_gen_as_roots" is false, younger generations are - // not scanned as roots; in this case, the caller must be arranging to - // scan the younger generations itself. (For example, a generation might - // explicitly mark reachable objects in younger generations, to avoid - // excess storage retention.) - void cms_process_roots(StrongRootsScope* scope, - bool young_gen_as_roots, - ScanningOption so, - bool only_strong_roots, - OopsInGenClosure* root_closure, - CLDClosure* cld_closure); - void full_process_roots(StrongRootsScope* scope, bool is_adjust_phase, ScanningOption so, @@ -479,12 +483,8 @@ public: oop obj, size_t obj_size); -private: - // Accessor for memory state verification support - NOT_PRODUCT( - static size_t skip_header_HeapWords() { return _skip_header_HeapWords; } - ) +private: // Override void check_for_non_bad_heap_word_value(HeapWord* addr, size_t size) PRODUCT_RETURN; @@ -499,22 +499,8 @@ private: // collect() and collect_locked(). Caller holds the Heap_lock on entry. void collect_locked(GCCause::Cause cause, GenerationType max_generation); - // Returns success or failure. - bool create_cms_collector(); - - // In support of ExplicitGCInvokesConcurrent functionality - bool should_do_concurrent_full_gc(GCCause::Cause cause); - void collect_mostly_concurrent(GCCause::Cause cause); - // Save the tops of the spaces in all generations void record_gen_tops_before_GC() PRODUCT_RETURN; - -protected: - void gc_prologue(bool full); - void gc_epilogue(bool full); - -public: - void stop(); }; #endif // SHARE_VM_GC_SHARED_GENCOLLECTEDHEAP_HPP diff --git a/src/hotspot/share/gc/shared/genOopClosures.hpp b/src/hotspot/share/gc/shared/genOopClosures.hpp index f1dd89344d8..076b2fdd031 100644 --- a/src/hotspot/share/gc/shared/genOopClosures.hpp +++ b/src/hotspot/share/gc/shared/genOopClosures.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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 @@ -81,24 +81,25 @@ class OopsInGenClosure : public ExtendedOopClosure { }; -// Super class for scan closures. It contains code to dirty scanned Klasses. -class OopsInKlassOrGenClosure: public OopsInGenClosure { - Klass* _scanned_klass; +// Super class for scan closures. It contains code to dirty scanned class loader data. +class OopsInClassLoaderDataOrGenClosure: public OopsInGenClosure { + ClassLoaderData* _scanned_cld; public: - OopsInKlassOrGenClosure(Generation* g) : OopsInGenClosure(g), _scanned_klass(NULL) {} - void set_scanned_klass(Klass* k) { - assert(k == NULL || _scanned_klass == NULL, "Must be"); - _scanned_klass = k; + OopsInClassLoaderDataOrGenClosure(Generation* g) : OopsInGenClosure(g), _scanned_cld(NULL) {} + void set_scanned_cld(ClassLoaderData* cld) { + assert(cld == NULL || _scanned_cld == NULL, "Must be"); + _scanned_cld = cld; } - bool is_scanning_a_klass() { return _scanned_klass != NULL; } - void do_klass_barrier(); + bool is_scanning_a_cld() { return _scanned_cld != NULL; } + void do_cld_barrier(); }; + // Closure for scanning DefNewGeneration. // // This closure will perform barrier store calls for ALL // pointers in scanned oops. -class ScanClosure: public OopsInKlassOrGenClosure { +class ScanClosure: public OopsInClassLoaderDataOrGenClosure { protected: DefNewGeneration* _g; HeapWord* _boundary; @@ -117,7 +118,7 @@ class ScanClosure: public OopsInKlassOrGenClosure { // This closure only performs barrier store calls on // pointers into the DefNewGeneration. This is less // precise, but faster, than a ScanClosure -class FastScanClosure: public OopsInKlassOrGenClosure { +class FastScanClosure: public OopsInClassLoaderDataOrGenClosure { protected: DefNewGeneration* _g; HeapWord* _boundary; @@ -131,14 +132,15 @@ class FastScanClosure: public OopsInKlassOrGenClosure { inline void do_oop_nv(narrowOop* p); }; -class KlassScanClosure: public KlassClosure { - OopsInKlassOrGenClosure* _scavenge_closure; +class CLDScanClosure: public CLDClosure { + OopsInClassLoaderDataOrGenClosure* _scavenge_closure; // true if the the modified oops state should be saved. - bool _accumulate_modified_oops; + bool _accumulate_modified_oops; public: - KlassScanClosure(OopsInKlassOrGenClosure* scavenge_closure, - KlassRemSet* klass_rem_set_policy); - void do_klass(Klass* k); + CLDScanClosure(OopsInClassLoaderDataOrGenClosure* scavenge_closure, + bool accumulate_modified_oops) : + _scavenge_closure(scavenge_closure), _accumulate_modified_oops(accumulate_modified_oops) {} + void do_cld(ClassLoaderData* cld); }; class FilteringClosure: public ExtendedOopClosure { diff --git a/src/hotspot/share/gc/shared/genOopClosures.inline.hpp b/src/hotspot/share/gc/shared/genOopClosures.inline.hpp index 13883f2283a..856d573f8f6 100644 --- a/src/hotspot/share/gc/shared/genOopClosures.inline.hpp +++ b/src/hotspot/share/gc/shared/genOopClosures.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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 @@ -68,9 +68,11 @@ template inline void OopsInGenClosure::par_do_barrier(T* p) { } } -inline void OopsInKlassOrGenClosure::do_klass_barrier() { - assert(_scanned_klass != NULL, "Must be"); - _scanned_klass->record_modified_oops(); +inline void OopsInClassLoaderDataOrGenClosure::do_cld_barrier() { + assert(_scanned_cld != NULL, "Must be"); + if (!_scanned_cld->has_modified_oops()) { + _scanned_cld->record_modified_oops(); + } } // NOTE! Any changes made here should also be made @@ -87,8 +89,8 @@ template inline void ScanClosure::do_oop_work(T* p) { oopDesc::encode_store_heap_oop_not_null(p, new_obj); } - if (is_scanning_a_klass()) { - do_klass_barrier(); + if (is_scanning_a_cld()) { + do_cld_barrier(); } else if (_gc_barrier) { // Now call parent closure do_barrier(p); @@ -111,8 +113,8 @@ template inline void FastScanClosure::do_oop_work(T* p) { oop new_obj = obj->is_forwarded() ? obj->forwardee() : _g->copy_to_survivor_space(obj); oopDesc::encode_store_heap_oop_not_null(p, new_obj); - if (is_scanning_a_klass()) { - do_klass_barrier(); + if (is_scanning_a_cld()) { + do_cld_barrier(); } else if (_gc_barrier) { // Now call parent closure do_barrier(p); diff --git a/src/hotspot/share/gc/shared/generation.cpp b/src/hotspot/share/gc/shared/generation.cpp index d86103ae077..68c92230729 100644 --- a/src/hotspot/share/gc/shared/generation.cpp +++ b/src/hotspot/share/gc/shared/generation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -94,22 +94,14 @@ void Generation::print_on(outputStream* st) const { p2i(_virtual_space.high_boundary())); } -void Generation::print_summary_info() { print_summary_info_on(tty); } - void Generation::print_summary_info_on(outputStream* st) { StatRecord* sr = stat_record(); double time = sr->accumulated_time.seconds(); - // I didn't want to change the logging when removing the level concept, - // but I guess this logging could say young/old or something instead of 0/1. - uint level; - if (GenCollectedHeap::heap()->is_young_gen(this)) { - level = 0; - } else { - level = 1; - } - st->print_cr("[Accumulated GC generation %d time %3.7f secs, " - "%u GC's, avg GC time %3.7f]", - level, time, sr->invocations, + st->print_cr("Accumulated %s generation GC time %3.7f secs, " + "%u GC's, avg GC time %3.7f", + GenCollectedHeap::heap()->is_young_gen(this) ? "young" : "old" , + time, + sr->invocations, sr->invocations > 0 ? time / sr->invocations : 0.0); } diff --git a/src/hotspot/share/gc/shared/generation.hpp b/src/hotspot/share/gc/shared/generation.hpp index 7507e7763b3..00d17a22a33 100644 --- a/src/hotspot/share/gc/shared/generation.hpp +++ b/src/hotspot/share/gc/shared/generation.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -549,7 +549,6 @@ private: public: StatRecord* stat_record() { return &_stat_record; } - virtual void print_summary_info(); virtual void print_summary_info_on(outputStream* st); // Performance Counter support diff --git a/src/hotspot/share/gc/shared/modRefBarrierSet.hpp b/src/hotspot/share/gc/shared/modRefBarrierSet.hpp index 8b65f610d4f..9c19f0a862b 100644 --- a/src/hotspot/share/gc/shared/modRefBarrierSet.hpp +++ b/src/hotspot/share/gc/shared/modRefBarrierSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -35,57 +35,12 @@ class OopClosure; class Generation; class ModRefBarrierSet: public BarrierSet { -public: - - // Barriers only on ref writes. - bool has_read_ref_barrier() { return false; } - bool has_read_prim_barrier() { return false; } - bool has_write_ref_barrier() { return true; } - bool has_write_prim_barrier() { return false; } - - bool read_ref_needs_barrier(void* field) { return false; } - bool read_prim_needs_barrier(HeapWord* field, size_t bytes) { return false; } - bool write_prim_needs_barrier(HeapWord* field, size_t bytes, - juint val1, juint val2) { return false; } - - void write_prim_field(oop obj, size_t offset, size_t bytes, - juint val1, juint val2) {} - - void read_ref_field(void* field) {} - void read_prim_field(HeapWord* field, size_t bytes) {} - protected: - ModRefBarrierSet(const BarrierSet::FakeRtti& fake_rtti) : BarrierSet(fake_rtti.add_tag(BarrierSet::ModRef)) { } ~ModRefBarrierSet() { } public: - void write_prim_field(HeapWord* field, size_t bytes, - juint val1, juint val2) {} - - bool has_read_ref_array_opt() { return false; } - bool has_read_prim_array_opt() { return false; } - bool has_write_prim_array_opt() { return false; } - - bool has_read_region_opt() { return false; } - - - // These operations should assert false unless the corresponding operation - // above returns true. - void read_ref_array(MemRegion mr) { - assert(false, "can't call"); - } - void read_prim_array(MemRegion mr) { - assert(false, "can't call"); - } - void write_prim_array(MemRegion mr) { - assert(false, "can't call"); - } - void read_region(MemRegion mr) { - assert(false, "can't call"); - } - // Causes all refs in "mr" to be assumed to be modified. virtual void invalidate(MemRegion mr) = 0; diff --git a/src/hotspot/share/gc/shared/plab.inline.hpp b/src/hotspot/share/gc/shared/plab.inline.hpp index 6963a7fd913..b523956950d 100644 --- a/src/hotspot/share/gc/shared/plab.inline.hpp +++ b/src/hotspot/share/gc/shared/plab.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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 @@ -43,19 +43,19 @@ inline HeapWord* PLAB::allocate_aligned(size_t word_sz, unsigned short alignment } void PLABStats::add_allocated(size_t v) { - Atomic::add_ptr(v, &_allocated); + Atomic::add(v, &_allocated); } void PLABStats::add_unused(size_t v) { - Atomic::add_ptr(v, &_unused); + Atomic::add(v, &_unused); } void PLABStats::add_wasted(size_t v) { - Atomic::add_ptr(v, &_wasted); + Atomic::add(v, &_wasted); } void PLABStats::add_undo_wasted(size_t v) { - Atomic::add_ptr(v, &_undo_wasted); + Atomic::add(v, &_undo_wasted); } #endif // SHARE_VM_GC_SHARED_PLAB_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/referenceProcessor.cpp b/src/hotspot/share/gc/shared/referenceProcessor.cpp index 64c0d6f163f..485e79ceb9a 100644 --- a/src/hotspot/share/gc/shared/referenceProcessor.cpp +++ b/src/hotspot/share/gc/shared/referenceProcessor.cpp @@ -36,7 +36,6 @@ #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" -#include "runtime/jniHandles.hpp" ReferencePolicy* ReferenceProcessor::_always_clear_soft_ref_policy = NULL; ReferencePolicy* ReferenceProcessor::_default_soft_ref_policy = NULL; @@ -245,51 +244,16 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references( is_alive, keep_alive, complete_gc, task_executor, phase_times); } - // Weak global JNI references. It would make more sense (semantically) to - // traverse these simultaneously with the regular weak references above, but - // that is not how the JDK1.2 specification is. See #4126360. Native code can - // thus use JNI weak references to circumvent the phantom references and - // resurrect a "post-mortem" object. - { - GCTraceTime(Debug, gc, ref) tt("JNI Weak Reference", phase_times->gc_timer()); - if (task_executor != NULL) { - task_executor->set_single_threaded_mode(); - } - process_phaseJNI(is_alive, keep_alive, complete_gc); + if (task_executor != NULL) { + // Record the work done by the parallel workers. + task_executor->set_single_threaded_mode(); } phase_times->set_total_time_ms((os::elapsedTime() - start_time) * 1000); - log_develop_trace(gc, ref)("JNI Weak Reference count: " SIZE_FORMAT, count_jni_refs()); - return stats; } -#ifndef PRODUCT -// Calculate the number of jni handles. -size_t ReferenceProcessor::count_jni_refs() { - class CountHandleClosure: public OopClosure { - private: - size_t _count; - public: - CountHandleClosure(): _count(0) {} - void do_oop(oop* unused) { _count++; } - void do_oop(narrowOop* unused) { ShouldNotReachHere(); } - size_t count() { return _count; } - }; - CountHandleClosure global_handle_count; - JNIHandles::weak_oops_do(&global_handle_count); - return global_handle_count.count(); -} -#endif - -void ReferenceProcessor::process_phaseJNI(BoolObjectClosure* is_alive, - OopClosure* keep_alive, - VoidClosure* complete_gc) { - JNIHandles::weak_oops_do(is_alive, keep_alive); - complete_gc->do_void(); -} - void ReferenceProcessor::enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor, ReferenceProcessorPhaseTimes* phase_times) { // Enqueue references that are not made active again, and diff --git a/src/hotspot/share/gc/shared/referenceProcessor.hpp b/src/hotspot/share/gc/shared/referenceProcessor.hpp index b5c034b13a7..274693ac860 100644 --- a/src/hotspot/share/gc/shared/referenceProcessor.hpp +++ b/src/hotspot/share/gc/shared/referenceProcessor.hpp @@ -246,10 +246,6 @@ class ReferenceProcessor : public CHeapObj { AbstractRefProcTaskExecutor* task_executor, ReferenceProcessorPhaseTimes* phase_times); - void process_phaseJNI(BoolObjectClosure* is_alive, - OopClosure* keep_alive, - VoidClosure* complete_gc); - // Work methods used by the method process_discovered_reflist // Phase1: keep alive all those referents that are otherwise // dead but which must be kept alive by policy (and their closure). @@ -341,9 +337,6 @@ class ReferenceProcessor : public CHeapObj { void clear_discovered_references(DiscoveredList& refs_list); - // Calculate the number of jni handles. - size_t count_jni_refs(); - void log_reflist_counts(DiscoveredList ref_lists[], uint active_length, size_t total_count) PRODUCT_RETURN; // Balances reference queues. diff --git a/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp b/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp index 2a026d15275..f0dc927339a 100644 --- a/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp +++ b/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp @@ -272,7 +272,7 @@ ReferenceProcessorPhaseTimes::~ReferenceProcessorPhaseTimes() { double ReferenceProcessorPhaseTimes::ref_proc_time_ms(ReferenceType ref_type) const { ASSERT_REF_TYPE(ref_type); - return _par_phase_time_ms[ref_type_2_index(ref_type)]; + return _ref_proc_time_ms[ref_type_2_index(ref_type)]; } void ReferenceProcessorPhaseTimes::set_ref_proc_time_ms(ReferenceType ref_type, diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index 0c7615b9d90..0a39aae230b 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -631,7 +631,7 @@ inline HeapWord* ContiguousSpace::par_allocate_impl(size_t size) { HeapWord* obj = top(); if (pointer_delta(end(), obj) >= size) { HeapWord* new_top = obj + size; - HeapWord* result = (HeapWord*)Atomic::cmpxchg_ptr(new_top, top_addr(), obj); + HeapWord* result = Atomic::cmpxchg(new_top, top_addr(), obj); // result can be one of two: // the old top value: the exchange succeeded // otherwise: the new value of the top is returned. diff --git a/src/hotspot/share/gc/g1/suspendibleThreadSet.cpp b/src/hotspot/share/gc/shared/suspendibleThreadSet.cpp similarity index 97% rename from src/hotspot/share/gc/g1/suspendibleThreadSet.cpp rename to src/hotspot/share/gc/shared/suspendibleThreadSet.cpp index de1f23e9155..50b8ea20752 100644 --- a/src/hotspot/share/gc/g1/suspendibleThreadSet.cpp +++ b/src/hotspot/share/gc/shared/suspendibleThreadSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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,7 +23,7 @@ */ #include "precompiled.hpp" -#include "gc/g1/suspendibleThreadSet.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/semaphore.hpp" #include "runtime/thread.inline.hpp" diff --git a/src/hotspot/share/gc/g1/suspendibleThreadSet.hpp b/src/hotspot/share/gc/shared/suspendibleThreadSet.hpp similarity index 93% rename from src/hotspot/share/gc/g1/suspendibleThreadSet.hpp rename to src/hotspot/share/gc/shared/suspendibleThreadSet.hpp index bd440f4e706..1e47c3b57a8 100644 --- a/src/hotspot/share/gc/g1/suspendibleThreadSet.hpp +++ b/src/hotspot/share/gc/shared/suspendibleThreadSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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 @@ -22,8 +22,8 @@ * */ -#ifndef SHARE_VM_GC_G1_SUSPENDIBLETHREADSET_HPP -#define SHARE_VM_GC_G1_SUSPENDIBLETHREADSET_HPP +#ifndef SHARE_GC_SHARED_SUSPENDIBLETHREADSET_HPP +#define SHARE_GC_SHARED_SUSPENDIBLETHREADSET_HPP #include "memory/allocation.hpp" @@ -116,4 +116,4 @@ public: } }; -#endif // SHARE_VM_GC_G1_SUSPENDIBLETHREADSET_HPP +#endif // SHARE_GC_SHARED_SUSPENDIBLETHREADSET_HPP diff --git a/src/hotspot/share/gc/shared/taskqueue.inline.hpp b/src/hotspot/share/gc/shared/taskqueue.inline.hpp index f6f59b89315..22f185c3860 100644 --- a/src/hotspot/share/gc/shared/taskqueue.inline.hpp +++ b/src/hotspot/share/gc/shared/taskqueue.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -259,9 +259,7 @@ GenericTaskQueueSet::steal(uint queue_num, int* seed, E& t) { template inline typename TaskQueueSuper::Age TaskQueueSuper::Age::cmpxchg(const Age new_age, const Age old_age) volatile { - return (size_t) Atomic::cmpxchg_ptr((intptr_t)new_age._data, - (volatile intptr_t *)&_data, - (intptr_t)old_age._data); + return Atomic::cmpxchg(new_age._data, &_data, old_age._data); } template diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp index b004ba58c89..cf16f816659 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, 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 @@ -275,8 +275,7 @@ void ThreadLocalAllocBuffer::print_stats(const char* tag) { Thread* thrd = myThread(); size_t waste = _gc_waste + _slow_refill_waste + _fast_refill_waste; size_t alloc = _number_of_refills * _desired_size; - double waste_percent = alloc == 0 ? 0.0 : - 100.0 * waste / alloc; + double waste_percent = percent_of(waste, alloc); size_t tlab_used = Universe::heap()->tlab_used(thrd); log.trace("TLAB: %s thread: " INTPTR_FORMAT " [id: %2d]" " desired_size: " SIZE_FORMAT "KB" @@ -416,8 +415,7 @@ void GlobalTLABStats::print() { } size_t waste = _total_gc_waste + _total_slow_refill_waste + _total_fast_refill_waste; - double waste_percent = _total_allocation == 0 ? 0.0 : - 100.0 * waste / _total_allocation; + double waste_percent = percent_of(waste, _total_allocation); log.debug("TLAB totals: thrds: %d refills: %d max: %d" " slow allocs: %d max %d waste: %4.1f%%" " gc: " SIZE_FORMAT "B max: " SIZE_FORMAT "B" diff --git a/src/hotspot/share/shark/sharkInliner.hpp b/src/hotspot/share/gc/shared/weakProcessor.cpp similarity index 64% rename from src/hotspot/share/shark/sharkInliner.hpp rename to src/hotspot/share/gc/shared/weakProcessor.cpp index c683929665c..a04aada9e13 100644 --- a/src/hotspot/share/shark/sharkInliner.hpp +++ b/src/hotspot/share/gc/shared/weakProcessor.cpp @@ -1,6 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. + * Copyright (c) 2017, 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,20 +22,17 @@ * */ -#ifndef SHARE_VM_SHARK_SHARKINLINER_HPP -#define SHARE_VM_SHARK_SHARKINLINER_HPP +#include "precompiled.hpp" +#include "gc/shared/weakProcessor.hpp" +#include "prims/jvmtiExport.hpp" +#include "runtime/jniHandles.hpp" -#include "ci/ciMethod.hpp" -#include "memory/allocation.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkState.hpp" +void WeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive) { + JNIHandles::weak_oops_do(is_alive, keep_alive); + JvmtiExport::weak_oops_do(is_alive, keep_alive); +} -class SharkInliner : public AllStatic { - public: - static bool attempt_inline(ciMethod* target, SharkState* state); - - private: - static bool may_be_inlinable(ciMethod* target); -}; - -#endif // SHARE_VM_SHARK_SHARKINLINER_HPP +void WeakProcessor::oops_do(OopClosure* closure) { + AlwaysTrueClosure always_true; + weak_oops_do(&always_true, closure); +} diff --git a/src/hotspot/share/shark/sharkEntry.hpp b/src/hotspot/share/gc/shared/weakProcessor.hpp similarity index 51% rename from src/hotspot/share/shark/sharkEntry.hpp rename to src/hotspot/share/gc/shared/weakProcessor.hpp index e0f535c6914..1f5837fb197 100644 --- a/src/hotspot/share/shark/sharkEntry.hpp +++ b/src/hotspot/share/gc/shared/weakProcessor.hpp @@ -1,6 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. + * Copyright (c) 2017, 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,43 +22,25 @@ * */ -#ifndef SHARE_VM_SHARK_SHARKENTRY_HPP -#define SHARE_VM_SHARK_SHARKENTRY_HPP +#ifndef SHARE_VM_GC_SHARED_WEAKPROCESSOR_HPP +#define SHARE_VM_GC_SHARED_WEAKPROCESSOR_HPP -#include "shark/llvmHeaders.hpp" +#include "memory/allocation.hpp" +#include "memory/iterator.hpp" -class SharkContext; +// Helper class to aid in root scanning and cleaning of weak oops in the VM. +// +// New containers of weak oops added to this class will automatically +// be cleaned by all GCs, including the young generation GCs. +class WeakProcessor : AllStatic { +public: + // Visit all oop*s and apply the keep_alive closure if the referenced + // object is considered alive by the is_alive closure, otherwise do some + // container specific cleanup of element holding the oop. + static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive); -class SharkEntry : public ZeroEntry { - private: - address _code_limit; - SharkContext* _context; - llvm::Function* _function; - - public: - address code_start() const { - return entry_point(); - } - address code_limit() const { - return _code_limit; - } - SharkContext* context() const { - return _context; - } - llvm::Function* function() const { - return _function; - } - - public: - void set_code_limit(address code_limit) { - _code_limit = code_limit; - } - void set_context(SharkContext* context) { - _context = context; - } - void set_function(llvm::Function* function) { - _function = function; - } + // Visit all oop*s and apply the given closure. + static void oops_do(OopClosure* closure); }; -#endif // SHARE_VM_SHARK_SHARKENTRY_HPP +#endif // SHARE_VM_GC_SHARED_WEAKPROCESSOR_HPP diff --git a/src/hotspot/share/interpreter/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/bytecodeInterpreter.cpp index 821b8cc1ef8..d130142c47a 100644 --- a/src/hotspot/share/interpreter/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/bytecodeInterpreter.cpp @@ -478,9 +478,7 @@ BytecodeInterpreter::run(interpreterState istate) { #ifdef ASSERT if (istate->_msg != initialize) { assert(labs(istate->_stack_base - istate->_stack_limit) == (istate->_method->max_stack() + 1), "bad stack limit"); -#ifndef SHARK IA32_ONLY(assert(istate->_stack_limit == istate->_thread->last_Java_sp() + 1, "wrong")); -#endif // !SHARK } // Verify linkages. interpreterState l = istate; @@ -705,7 +703,7 @@ BytecodeInterpreter::run(interpreterState istate) { if (hash != markOopDesc::no_hash) { header = header->copy_set_hash(hash); } - if (Atomic::cmpxchg_ptr(header, rcvr->mark_addr(), mark) == mark) { + if (Atomic::cmpxchg(header, rcvr->mark_addr(), mark) == mark) { if (PrintBiasedLockingStatistics) (*BiasedLocking::revoked_lock_entry_count_addr())++; } @@ -715,7 +713,7 @@ BytecodeInterpreter::run(interpreterState istate) { if (hash != markOopDesc::no_hash) { new_header = new_header->copy_set_hash(hash); } - if (Atomic::cmpxchg_ptr((void*)new_header, rcvr->mark_addr(), mark) == mark) { + if (Atomic::cmpxchg(new_header, rcvr->mark_addr(), mark) == mark) { if (PrintBiasedLockingStatistics) { (* BiasedLocking::rebiased_lock_entry_count_addr())++; } @@ -734,7 +732,7 @@ BytecodeInterpreter::run(interpreterState istate) { markOop new_header = (markOop) ((uintptr_t) header | thread_ident); // Debugging hint. DEBUG_ONLY(mon->lock()->set_displaced_header((markOop) (uintptr_t) 0xdeaddead);) - if (Atomic::cmpxchg_ptr((void*)new_header, rcvr->mark_addr(), header) == header) { + if (Atomic::cmpxchg(new_header, rcvr->mark_addr(), header) == header) { if (PrintBiasedLockingStatistics) { (* BiasedLocking::anonymously_biased_lock_entry_count_addr())++; } @@ -750,7 +748,7 @@ BytecodeInterpreter::run(interpreterState istate) { markOop displaced = rcvr->mark()->set_unlocked(); mon->lock()->set_displaced_header(displaced); bool call_vm = UseHeavyMonitors; - if (call_vm || Atomic::cmpxchg_ptr(mon, rcvr->mark_addr(), displaced) != displaced) { + if (call_vm || Atomic::cmpxchg((markOop)mon, rcvr->mark_addr(), displaced) != displaced) { // Is it simple recursive case? if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) { mon->lock()->set_displaced_header(NULL); @@ -903,7 +901,7 @@ BytecodeInterpreter::run(interpreterState istate) { if (hash != markOopDesc::no_hash) { header = header->copy_set_hash(hash); } - if (Atomic::cmpxchg_ptr(header, lockee->mark_addr(), mark) == mark) { + if (Atomic::cmpxchg(header, lockee->mark_addr(), mark) == mark) { if (PrintBiasedLockingStatistics) { (*BiasedLocking::revoked_lock_entry_count_addr())++; } @@ -914,7 +912,7 @@ BytecodeInterpreter::run(interpreterState istate) { if (hash != markOopDesc::no_hash) { new_header = new_header->copy_set_hash(hash); } - if (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), mark) == mark) { + if (Atomic::cmpxchg(new_header, lockee->mark_addr(), mark) == mark) { if (PrintBiasedLockingStatistics) { (* BiasedLocking::rebiased_lock_entry_count_addr())++; } @@ -932,7 +930,7 @@ BytecodeInterpreter::run(interpreterState istate) { markOop new_header = (markOop) ((uintptr_t) header | thread_ident); // debugging hint DEBUG_ONLY(entry->lock()->set_displaced_header((markOop) (uintptr_t) 0xdeaddead);) - if (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), header) == header) { + if (Atomic::cmpxchg(new_header, lockee->mark_addr(), header) == header) { if (PrintBiasedLockingStatistics) { (* BiasedLocking::anonymously_biased_lock_entry_count_addr())++; } @@ -948,7 +946,7 @@ BytecodeInterpreter::run(interpreterState istate) { markOop displaced = lockee->mark()->set_unlocked(); entry->lock()->set_displaced_header(displaced); bool call_vm = UseHeavyMonitors; - if (call_vm || Atomic::cmpxchg_ptr(entry, lockee->mark_addr(), displaced) != displaced) { + if (call_vm || Atomic::cmpxchg((markOop)entry, lockee->mark_addr(), displaced) != displaced) { // Is it simple recursive case? if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) { entry->lock()->set_displaced_header(NULL); @@ -1844,7 +1842,7 @@ run: if (hash != markOopDesc::no_hash) { header = header->copy_set_hash(hash); } - if (Atomic::cmpxchg_ptr(header, lockee->mark_addr(), mark) == mark) { + if (Atomic::cmpxchg(header, lockee->mark_addr(), mark) == mark) { if (PrintBiasedLockingStatistics) (*BiasedLocking::revoked_lock_entry_count_addr())++; } @@ -1855,7 +1853,7 @@ run: if (hash != markOopDesc::no_hash) { new_header = new_header->copy_set_hash(hash); } - if (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), mark) == mark) { + if (Atomic::cmpxchg(new_header, lockee->mark_addr(), mark) == mark) { if (PrintBiasedLockingStatistics) (* BiasedLocking::rebiased_lock_entry_count_addr())++; } @@ -1875,7 +1873,7 @@ run: markOop new_header = (markOop) ((uintptr_t) header | thread_ident); // debugging hint DEBUG_ONLY(entry->lock()->set_displaced_header((markOop) (uintptr_t) 0xdeaddead);) - if (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), header) == header) { + if (Atomic::cmpxchg(new_header, lockee->mark_addr(), header) == header) { if (PrintBiasedLockingStatistics) (* BiasedLocking::anonymously_biased_lock_entry_count_addr())++; } @@ -1891,7 +1889,7 @@ run: markOop displaced = lockee->mark()->set_unlocked(); entry->lock()->set_displaced_header(displaced); bool call_vm = UseHeavyMonitors; - if (call_vm || Atomic::cmpxchg_ptr(entry, lockee->mark_addr(), displaced) != displaced) { + if (call_vm || Atomic::cmpxchg((markOop)entry, lockee->mark_addr(), displaced) != displaced) { // Is it simple recursive case? if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) { entry->lock()->set_displaced_header(NULL); @@ -1923,7 +1921,8 @@ run: bool call_vm = UseHeavyMonitors; // If it isn't recursive we either must swap old header or call the runtime if (header != NULL || call_vm) { - if (call_vm || Atomic::cmpxchg_ptr(header, lockee->mark_addr(), lock) != lock) { + markOop old_header = markOopDesc::encode(lock); + if (call_vm || lockee->cas_set_mark(header, old_header) != old_header) { // restore object for the slow case most_recent->set_obj(lockee); CALL_VM(InterpreterRuntime::monitorexit(THREAD, most_recent), handle_exception); @@ -2189,7 +2188,7 @@ run: HeapWord* compare_to = *Universe::heap()->top_addr(); HeapWord* new_top = compare_to + obj_size; if (new_top <= *Universe::heap()->end_addr()) { - if (Atomic::cmpxchg_ptr(new_top, Universe::heap()->top_addr(), compare_to) != compare_to) { + if (Atomic::cmpxchg(new_top, Universe::heap()->top_addr(), compare_to) != compare_to) { goto retry; } result = (oop) compare_to; @@ -2975,7 +2974,8 @@ run: if (!lockee->mark()->has_bias_pattern()) { // If it isn't recursive we either must swap old header or call the runtime if (header != NULL) { - if (Atomic::cmpxchg_ptr(header, lockee->mark_addr(), lock) != lock) { + markOop old_header = markOopDesc::encode(lock); + if (lockee->cas_set_mark(header, old_header) != old_header) { // restore object for the slow case end->set_obj(lockee); { @@ -3050,7 +3050,8 @@ run: base->set_obj(NULL); // If it isn't recursive we either must swap old header or call the runtime if (header != NULL) { - if (Atomic::cmpxchg_ptr(header, rcvr->mark_addr(), lock) != lock) { + markOop old_header = markOopDesc::encode(lock); + if (rcvr->cas_set_mark(header, old_header) != old_header) { // restore object for the slow case base->set_obj(rcvr); { diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp index f0cbe034502..042de4ceca9 100644 --- a/src/hotspot/share/interpreter/linkResolver.cpp +++ b/src/hotspot/share/interpreter/linkResolver.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/defaultMethods.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/resolutionErrors.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" @@ -1696,8 +1697,22 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHan Handle bootstrap_specifier; // Check if CallSite has been bound already: ConstantPoolCacheEntry* cpce = pool->invokedynamic_cp_cache_entry_at(index); + int pool_index = cpce->constant_pool_index(); + if (cpce->is_f1_null()) { - int pool_index = cpce->constant_pool_index(); + if (cpce->indy_resolution_failed()) { + ConstantPool::throw_resolution_error(pool, + ResolutionErrorTable::encode_cpcache_index(index), + CHECK); + } + + // The initial step in Call Site Specifier Resolution is to resolve the symbolic + // reference to a method handle which will be the bootstrap method for a dynamic + // call site. If resolution for the java.lang.invoke.MethodHandle for the bootstrap + // method fails, then a MethodHandleInError is stored at the corresponding bootstrap + // method's CP index for the CONSTANT_MethodHandle_info. So, there is no need to + // set the indy_rf flag since any subsequent invokedynamic instruction which shares + // this bootstrap method will encounter the resolution of MethodHandleInError. oop bsm_info = pool->resolve_bootstrap_specifier_at(pool_index, THREAD); wrap_invokedynamic_exception(CHECK); assert(bsm_info != NULL, ""); @@ -1722,7 +1737,31 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHan tty->print(" BSM info: "); bootstrap_specifier->print(); } - resolve_dynamic_call(result, bootstrap_specifier, method_name, method_signature, current_klass, CHECK); + resolve_dynamic_call(result, bootstrap_specifier, method_name, + method_signature, current_klass, THREAD); + if (HAS_PENDING_EXCEPTION && PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) { + int encoded_index = ResolutionErrorTable::encode_cpcache_index(index); + bool recorded_res_status = cpce->save_and_throw_indy_exc(pool, pool_index, + encoded_index, + pool()->tag_at(pool_index), + CHECK); + if (!recorded_res_status) { + // Another thread got here just before we did. So, either use the method + // that it resolved or throw the LinkageError exception that it threw. + if (!cpce->is_f1_null()) { + methodHandle method( THREAD, cpce->f1_as_method()); + Handle appendix( THREAD, cpce->appendix_if_resolved(pool)); + Handle method_type(THREAD, cpce->method_type_if_resolved(pool)); + result.set_handle(method, appendix, method_type, THREAD); + wrap_invokedynamic_exception(CHECK); + } else { + assert(cpce->indy_resolution_failed(), "Resolution failure flag not set"); + ConstantPool::throw_resolution_error(pool, encoded_index, CHECK); + } + return; + } + assert(cpce->indy_resolution_failed(), "Resolution failure flag wasn't set"); + } } void LinkResolver::resolve_dynamic_call(CallInfo& result, diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 26a2916d4f5..58af707b7e7 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -448,11 +448,11 @@ OopMapCache::~OopMapCache() { } OopMapCacheEntry* OopMapCache::entry_at(int i) const { - return (OopMapCacheEntry*)OrderAccess::load_ptr_acquire(&(_array[i % _size])); + return OrderAccess::load_acquire(&(_array[i % _size])); } bool OopMapCache::put_at(int i, OopMapCacheEntry* entry, OopMapCacheEntry* old) { - return Atomic::cmpxchg_ptr (entry, &_array[i % _size], old) == old; + return Atomic::cmpxchg(entry, &_array[i % _size], old) == old; } void OopMapCache::flush() { @@ -564,7 +564,7 @@ void OopMapCache::enqueue_for_cleanup(OopMapCacheEntry* entry) { do { head = _old_entries; entry->_next = head; - success = Atomic::cmpxchg_ptr (entry, &_old_entries, head) == head; + success = Atomic::cmpxchg(entry, &_old_entries, head) == head; } while (!success); if (log_is_enabled(Debug, interpreter, oopmap)) { diff --git a/src/hotspot/share/interpreter/templateInterpreter.cpp b/src/hotspot/share/interpreter/templateInterpreter.cpp index b8feaa786f7..eed92712146 100644 --- a/src/hotspot/share/interpreter/templateInterpreter.cpp +++ b/src/hotspot/share/interpreter/templateInterpreter.cpp @@ -54,6 +54,8 @@ void TemplateInterpreter::initialize() { _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL, "Interpreter"); TemplateInterpreterGenerator g(_code); + // Free the unused memory not occupied by the interpreter and the stubs + _code->deallocate_unused_tail(); } if (PrintInterpreter) { diff --git a/src/hotspot/share/jvmci/compilerRuntime.cpp b/src/hotspot/share/jvmci/compilerRuntime.cpp index 80cf344f4c0..f01de93ea8c 100644 --- a/src/hotspot/share/jvmci/compilerRuntime.cpp +++ b/src/hotspot/share/jvmci/compilerRuntime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -24,10 +24,14 @@ #include "precompiled.hpp" #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" +#include "interpreter/linkResolver.hpp" #include "jvmci/compilerRuntime.hpp" +#include "oops/oop.inline.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" #include "runtime/interfaceSupport.hpp" +#include "runtime/vframe.hpp" +#include "aot/aotLoader.hpp" // Resolve and allocate String JRT_BLOCK_ENTRY(void, CompilerRuntime::resolve_string_by_symbol(JavaThread *thread, void* string_result, const char* name)) @@ -119,6 +123,62 @@ Method* CompilerRuntime::resolve_method_helper(Klass* klass, const char* method_ return m; } +JRT_BLOCK_ENTRY(void, CompilerRuntime::resolve_dynamic_invoke(JavaThread *thread, oop* appendix_result)) + JRT_BLOCK + { + ResourceMark rm(THREAD); + vframeStream vfst(thread, true); // Do not skip and javaCalls + assert(!vfst.at_end(), "Java frame must exist"); + methodHandle caller(THREAD, vfst.method()); + InstanceKlass* holder = caller->method_holder(); + int bci = vfst.bci(); + Bytecode_invoke bytecode(caller, bci); + int index = bytecode.index(); + + // Make sure it's resolved first + CallInfo callInfo; + constantPoolHandle cp(holder->constants()); + ConstantPoolCacheEntry* cp_cache_entry = cp->cache()->entry_at(cp->decode_cpcache_index(index, true)); + Bytecodes::Code invoke_code = bytecode.invoke_code(); + if (!cp_cache_entry->is_resolved(invoke_code)) { + LinkResolver::resolve_invoke(callInfo, Handle(), cp, index, invoke_code, CHECK); + if (bytecode.is_invokedynamic()) { + cp_cache_entry->set_dynamic_call(cp, callInfo); + } else { + cp_cache_entry->set_method_handle(cp, callInfo); + } + vmassert(cp_cache_entry->is_resolved(invoke_code), "sanity"); + } + + Handle appendix(THREAD, cp_cache_entry->appendix_if_resolved(cp)); + Klass *appendix_klass = appendix.is_null() ? NULL : appendix->klass(); + + methodHandle adapter_method(cp_cache_entry->f1_as_method()); + InstanceKlass *adapter_klass = adapter_method->method_holder(); + + if (appendix_klass != NULL && appendix_klass->is_instance_klass()) { + vmassert(InstanceKlass::cast(appendix_klass)->is_initialized(), "sanity"); + } + if (!adapter_klass->is_initialized()) { + // Force initialization of adapter class + adapter_klass->initialize(CHECK); + // Double-check that it was really initialized, + // because we could be doing a recursive call + // from inside . + } + + int cpi = cp_cache_entry->constant_pool_index(); + if (!AOTLoader::reconcile_dynamic_invoke(holder, cpi, adapter_method(), + appendix_klass)) { + return; + } + + *appendix_result = appendix(); + thread->set_vm_result(appendix()); + } + JRT_BLOCK_END +JRT_END + JRT_BLOCK_ENTRY(MethodCounters*, CompilerRuntime::resolve_method_by_symbol_and_load_counters(JavaThread *thread, MethodCounters** counters_result, Klass* klass, const char* data)) MethodCounters* c = *counters_result; // Is it resolved already? JRT_BLOCK diff --git a/src/hotspot/share/jvmci/compilerRuntime.hpp b/src/hotspot/share/jvmci/compilerRuntime.hpp index 1e3d70873f8..c9688a726a2 100644 --- a/src/hotspot/share/jvmci/compilerRuntime.hpp +++ b/src/hotspot/share/jvmci/compilerRuntime.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -39,6 +39,8 @@ class CompilerRuntime : AllStatic { const char* signature_name, int signature_name_len); // Resolution methods for aot compiled code. static void resolve_string_by_symbol(JavaThread *thread, void* string_result, const char* name); + static void resolve_dynamic_invoke(JavaThread *thread, oop* appendix_result); + static Klass* resolve_klass_by_symbol(JavaThread *thread, Klass** klass_result, const char* name); static Klass* initialize_klass_by_symbol(JavaThread *thread, Klass** klass_result, const char* name); static MethodCounters* resolve_method_by_symbol_and_load_counters(JavaThread *thread, MethodCounters** counters_result, Klass* klass_hint, const char* data); diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index 2ab2e067304..977ff966735 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -174,43 +174,42 @@ OopMap* CodeInstaller::create_oop_map(Handle debug_info, TRAPS) { } AOTOopRecorder::AOTOopRecorder(Arena* arena, bool deduplicate) : OopRecorder(arena, deduplicate) { - _meta_strings = new GrowableArray(); + _meta_refs = new GrowableArray(); } -int AOTOopRecorder::nr_meta_strings() const { - return _meta_strings->length(); +int AOTOopRecorder::nr_meta_refs() const { + return _meta_refs->length(); } -const char* AOTOopRecorder::meta_element(int pos) const { - return _meta_strings->at(pos); +jobject AOTOopRecorder::meta_element(int pos) const { + return _meta_refs->at(pos); } int AOTOopRecorder::find_index(Metadata* h) { + JavaThread* THREAD = JavaThread::current(); + int oldCount = metadata_count(); int index = this->OopRecorder::find_index(h); + int newCount = metadata_count(); + + if (oldCount == newCount) { + // found a match + return index; + } + + vmassert(index + 1 == newCount, "must be last"); Klass* klass = NULL; + oop result = NULL; if (h->is_klass()) { klass = (Klass*) h; - record_meta_string(klass->signature_name(), index); + result = CompilerToVM::get_jvmci_type(klass, CATCH); } else if (h->is_method()) { Method* method = (Method*) h; - // Need klass->signature_name() in method name - klass = method->method_holder(); - const char* klass_name = klass->signature_name(); - int klass_name_len = (int)strlen(klass_name); - Symbol* method_name = method->name(); - Symbol* signature = method->signature(); - int method_name_len = method_name->utf8_length(); - int method_sign_len = signature->utf8_length(); - int len = klass_name_len + 1 + method_name_len + method_sign_len; - char* dest = NEW_RESOURCE_ARRAY(char, len + 1); - strcpy(dest, klass_name); - dest[klass_name_len] = '.'; - strcpy(&dest[klass_name_len + 1], method_name->as_C_string()); - strcpy(&dest[klass_name_len + 1 + method_name_len], signature->as_C_string()); - dest[len] = 0; - record_meta_string(dest, index); + methodHandle mh(method); + result = CompilerToVM::get_jvmci_method(method, CATCH); } + jobject ref = JNIHandles::make_local(THREAD, result); + record_meta_ref(ref, index); return index; } @@ -224,16 +223,12 @@ int AOTOopRecorder::find_index(jobject h) { return find_index(klass); } -void AOTOopRecorder::record_meta_string(const char* name, int index) { +void AOTOopRecorder::record_meta_ref(jobject o, int index) { assert(index > 0, "must be 1..n"); index -= 1; // reduce by one to convert to array index - if (index < _meta_strings->length()) { - assert(strcmp(name, _meta_strings->at(index)) == 0, "must match"); - } else { - assert(index == _meta_strings->length(), "must be last"); - _meta_strings->append(name); - } + assert(index == _meta_refs->length(), "must be last"); + _meta_refs->append(o); } void* CodeInstaller::record_metadata_reference(CodeSection* section, address dest, Handle constant, TRAPS) { diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp index 73dda555acf..acc391ec1ac 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp @@ -49,13 +49,13 @@ public: virtual int find_index(Metadata* h); virtual int find_index(jobject h); - int nr_meta_strings() const; - const char* meta_element(int pos) const; + int nr_meta_refs() const; + jobject meta_element(int pos) const; private: - void record_meta_string(const char* name, int index); + void record_meta_ref(jobject ref, int index); - GrowableArray* _meta_strings; + GrowableArray* _meta_refs; }; class CodeMetadata { diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 0e5fc74ba32..ca65c1d6414 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -412,6 +412,7 @@ C2V_VMENTRY(jobjectArray, readConfiguration, (JNIEnv *env)) } else if (strcmp(vmField.typeString, "address") == 0 || strcmp(vmField.typeString, "intptr_t") == 0 || strcmp(vmField.typeString, "uintptr_t") == 0 || + strcmp(vmField.typeString, "OopHandle") == 0 || strcmp(vmField.typeString, "size_t") == 0 || // All foo* types are addresses. vmField.typeString[strlen(vmField.typeString) - 1] == '*') { @@ -1117,13 +1118,15 @@ C2V_VMENTRY(jint, getMetadata, (JNIEnv *jniEnv, jobject, jobject target, jobject AOTOopRecorder* recorder = code_metadata.get_oop_recorder(); - int nr_meta_strings = recorder->nr_meta_strings(); - objArrayOop metadataArray = oopFactory::new_objectArray(nr_meta_strings, CHECK_(JVMCIEnv::cache_full)); + int nr_meta_refs = recorder->nr_meta_refs(); + objArrayOop metadataArray = oopFactory::new_objectArray(nr_meta_refs, CHECK_(JVMCIEnv::cache_full)); objArrayHandle metadataArrayHandle(THREAD, metadataArray); - for (int i = 0; i < nr_meta_strings; ++i) { - const char* element = recorder->meta_element(i); - Handle java_string = java_lang_String::create_from_str(element, CHECK_(JVMCIEnv::cache_full)); - metadataArrayHandle->obj_at_put(i, java_string()); + for (int i = 0; i < nr_meta_refs; ++i) { + jobject element = recorder->meta_element(i); + if (element == NULL) { + return JVMCIEnv::cache_full; + } + metadataArrayHandle->obj_at_put(i, JNIHandles::resolve(element)); } HotSpotMetaData::set_metadata(metadata_handle, metadataArrayHandle()); @@ -1518,6 +1521,48 @@ C2V_VMENTRY(void, resolveInvokeHandleInPool, (JNIEnv*, jobject, jobject jvmci_co } C2V_END +C2V_VMENTRY(jint, isResolvedInvokeHandleInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + ConstantPoolCacheEntry* cp_cache_entry = cp->cache()->entry_at(cp->decode_cpcache_index(index)); + if (cp_cache_entry->is_resolved(Bytecodes::_invokehandle)) { + // MethodHandle.invoke* --> LambdaForm? + ResourceMark rm; + + LinkInfo link_info(cp, index, CATCH); + + Klass* resolved_klass = link_info.resolved_klass(); + + Symbol* name_sym = cp->name_ref_at(index); + + vmassert(MethodHandles::is_method_handle_invoke_name(resolved_klass, name_sym), "!"); + vmassert(MethodHandles::is_signature_polymorphic_name(resolved_klass, name_sym), "!"); + + methodHandle adapter_method(cp_cache_entry->f1_as_method()); + + methodHandle resolved_method(adapter_method); + + // Can we treat it as a regular invokevirtual? + if (resolved_method->method_holder() == resolved_klass && resolved_method->name() == name_sym) { + vmassert(!resolved_method->is_static(),"!"); + vmassert(MethodHandles::is_signature_polymorphic_method(resolved_method()),"!"); + vmassert(!MethodHandles::is_signature_polymorphic_static(resolved_method->intrinsic_id()), "!"); + vmassert(cp_cache_entry->appendix_if_resolved(cp) == NULL, "!"); + vmassert(cp_cache_entry->method_type_if_resolved(cp) == NULL, "!"); + + methodHandle m(LinkResolver::linktime_resolve_virtual_method_or_null(link_info)); + vmassert(m == resolved_method, "!!"); + return -1; + } + + return Bytecodes::_invokevirtual; + } + if (cp_cache_entry->is_resolved(Bytecodes::_invokedynamic)) { + return Bytecodes::_invokedynamic; + } + return -1; +C2V_END + + C2V_VMENTRY(jobject, getSignaturePolymorphicHolders, (JNIEnv*, jobject)) objArrayHandle holders = oopFactory::new_objArray_handle(SystemDictionary::String_klass(), 2, CHECK_NULL); Handle mh = java_lang_String::create_from_str("Ljava/lang/invoke/MethodHandle;", CHECK_NULL); @@ -1794,6 +1839,7 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL "I" HS_RESOLVED_METHOD "B[I)" HS_RESOLVED_KLASS, FN_PTR(resolveFieldInPool)}, {CC "resolveInvokeDynamicInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeDynamicInPool)}, {CC "resolveInvokeHandleInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeHandleInPool)}, + {CC "isResolvedInvokeHandleInPool", CC "(" HS_CONSTANT_POOL "I)I", FN_PTR(isResolvedInvokeHandleInPool)}, {CC "resolveMethod", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_METHOD HS_RESOLVED_KLASS ")" HS_RESOLVED_METHOD, FN_PTR(resolveMethod)}, {CC "getSignaturePolymorphicHolders", CC "()[" STRING, FN_PTR(getSignaturePolymorphicHolders)}, {CC "getVtableIndexForInterfaceMethod", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_METHOD ")I", FN_PTR(getVtableIndexForInterfaceMethod)}, diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp index c69b1ca37ad..27de63de573 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp @@ -24,7 +24,7 @@ #ifndef SHARE_VM_JVMCI_JVMCI_COMPILER_TO_VM_HPP #define SHARE_VM_JVMCI_JVMCI_COMPILER_TO_VM_HPP -#include "prims/jni.h" +#include "jni.h" #include "runtime/javaCalls.hpp" #include "jvmci/jvmciJavaClasses.hpp" diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp index 58764147efa..a4b856e3e06 100644 --- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -299,7 +299,7 @@ class JVMCIJavaClasses : AllStatic { typeArrayOop_field(HotSpotMetaData, relocBytes, "[B") \ typeArrayOop_field(HotSpotMetaData, exceptionBytes, "[B") \ typeArrayOop_field(HotSpotMetaData, oopMaps, "[B") \ - objArrayOop_field(HotSpotMetaData, metadata, "[Ljava/lang/String;") \ + objArrayOop_field(HotSpotMetaData, metadata, "[Ljava/lang/Object;") \ end_class \ start_class(HotSpotConstantPool) \ long_field(HotSpotConstantPool, metaspaceConstantPool) \ diff --git a/src/hotspot/share/jvmci/vmStructs_compiler_runtime.hpp b/src/hotspot/share/jvmci/vmStructs_compiler_runtime.hpp index 6e47bbd7a97..3cb5040030c 100644 --- a/src/hotspot/share/jvmci/vmStructs_compiler_runtime.hpp +++ b/src/hotspot/share/jvmci/vmStructs_compiler_runtime.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -28,6 +28,7 @@ #include "jvmci/compilerRuntime.hpp" #define VM_ADDRESSES_COMPILER_RUNTIME(declare_address, declare_preprocessor_address, declare_function) \ + declare_function(CompilerRuntime::resolve_dynamic_invoke) \ declare_function(CompilerRuntime::resolve_string_by_symbol) \ declare_function(CompilerRuntime::resolve_klass_by_symbol) \ declare_function(CompilerRuntime::resolve_method_by_symbol_and_load_counters) \ diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index a048fd22218..66a9d859ed0 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -33,6 +33,7 @@ #include "jvmci/vmStructs_compiler_runtime.hpp" #include "jvmci/vmStructs_jvmci.hpp" #include "oops/oop.hpp" +#include "oops/oopHandle.hpp" #include "oops/objArrayKlass.hpp" #include "runtime/globals.hpp" #include "runtime/sharedRuntime.hpp" @@ -124,6 +125,7 @@ nonstatic_field(ConstMethod, _code_size, u2) \ nonstatic_field(ConstMethod, _name_index, u2) \ nonstatic_field(ConstMethod, _signature_index, u2) \ + nonstatic_field(ConstMethod, _method_idnum, u2) \ nonstatic_field(ConstMethod, _max_stack, u2) \ nonstatic_field(ConstMethod, _max_locals, u2) \ \ @@ -156,6 +158,7 @@ nonstatic_field(InstanceKlass, _constants, ConstantPool*) \ nonstatic_field(InstanceKlass, _source_file_name_index, u2) \ nonstatic_field(InstanceKlass, _init_state, u1) \ + nonstatic_field(InstanceKlass, _misc_flags, u2) \ \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_sp, intptr_t*) \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_pc, address) \ @@ -192,7 +195,7 @@ nonstatic_field(Klass, _name, Symbol*) \ nonstatic_field(Klass, _prototype_header, markOop) \ nonstatic_field(Klass, _next_sibling, Klass*) \ - nonstatic_field(Klass, _java_mirror, oop) \ + nonstatic_field(Klass, _java_mirror, OopHandle) \ nonstatic_field(Klass, _modifier_flags, jint) \ nonstatic_field(Klass, _access_flags, AccessFlags) \ \ @@ -520,6 +523,7 @@ \ declare_constant(InstanceKlass::linked) \ declare_constant(InstanceKlass::fully_initialized) \ + declare_constant(InstanceKlass::_misc_is_anonymous) \ \ declare_constant(JumpData::taken_off_set) \ declare_constant(JumpData::displacement_off_set) \ @@ -761,6 +765,14 @@ declare_constant(VM_Version::ISA_XMONT) \ declare_constant(VM_Version::ISA_PAUSE_NSEC) \ declare_constant(VM_Version::ISA_VAMASK) \ + declare_constant(VM_Version::ISA_SPARC6) \ + declare_constant(VM_Version::ISA_DICTUNP) \ + declare_constant(VM_Version::ISA_FPCMPSHL) \ + declare_constant(VM_Version::ISA_RLE) \ + declare_constant(VM_Version::ISA_SHA3) \ + declare_constant(VM_Version::ISA_VIS3C) \ + declare_constant(VM_Version::ISA_SPARC5B) \ + declare_constant(VM_Version::ISA_MME) \ declare_constant(VM_Version::CPU_FAST_IDIV) \ declare_constant(VM_Version::CPU_FAST_RDPC) \ declare_constant(VM_Version::CPU_FAST_BIS) \ diff --git a/src/hotspot/share/memory/allocation.hpp b/src/hotspot/share/memory/allocation.hpp index aedaf90155b..01e44c5d7f1 100644 --- a/src/hotspot/share/memory/allocation.hpp +++ b/src/hotspot/share/memory/allocation.hpp @@ -233,7 +233,6 @@ class MetaspaceObj { void print_address_on(outputStream* st) const; // nonvirtual address printing #define METASPACE_OBJ_TYPES_DO(f) \ - f(Unknown) \ f(Class) \ f(Symbol) \ f(TypeArrayU1) \ diff --git a/src/hotspot/share/memory/filemap.cpp b/src/hotspot/share/memory/filemap.cpp index e45401f01d8..e4127d05b4e 100644 --- a/src/hotspot/share/memory/filemap.cpp +++ b/src/hotspot/share/memory/filemap.cpp @@ -182,6 +182,7 @@ void FileMapInfo::FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment _obj_alignment = ObjectAlignmentInBytes; _compact_strings = CompactStrings; _narrow_oop_mode = Universe::narrow_oop_mode(); + _narrow_oop_base = Universe::narrow_oop_base(); _narrow_oop_shift = Universe::narrow_oop_shift(); _max_heap_size = MaxHeapSize; _narrow_klass_base = Universe::narrow_klass_base(); @@ -687,8 +688,14 @@ static int num_open_archive_heap_ranges = 0; // open archive objects. void FileMapInfo::map_heap_regions() { if (MetaspaceShared::is_heap_object_archiving_allowed()) { + log_info(cds)("Archived narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d", + narrow_oop_mode(), p2i(narrow_oop_base()), narrow_oop_shift()); + log_info(cds)("Archived narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d", + p2i(narrow_klass_base()), narrow_klass_shift()); + // Check that all the narrow oop and klass encodings match the archive if (narrow_oop_mode() != Universe::narrow_oop_mode() || + narrow_oop_base() != Universe::narrow_oop_base() || narrow_oop_shift() != Universe::narrow_oop_shift() || narrow_klass_base() != Universe::narrow_klass_base() || narrow_klass_shift() != Universe::narrow_klass_shift()) { @@ -697,6 +704,11 @@ void FileMapInfo::map_heap_regions() { "The current CompressedOops/CompressedClassPointers encoding differs from " "that archived due to heap size change. The archive was dumped using max heap " "size " UINTX_FORMAT "M.", max_heap_size()/M); + log_info(cds)("Current narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d", + Universe::narrow_oop_mode(), p2i(Universe::narrow_oop_base()), + Universe::narrow_oop_shift()); + log_info(cds)("Current narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d", + p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift()); } } else { // First, map string regions as closed archive heap regions. diff --git a/src/hotspot/share/memory/filemap.hpp b/src/hotspot/share/memory/filemap.hpp index f636e64b1b7..5751747a0a2 100644 --- a/src/hotspot/share/memory/filemap.hpp +++ b/src/hotspot/share/memory/filemap.hpp @@ -60,7 +60,7 @@ public: return _timestamp != 0; } bool is_dir() { return _is_dir; } - bool is_jrt() { return ClassLoader::is_jrt(name()); } + bool is_modules_image() { return ClassLoader::is_modules_image(name()); } time_t timestamp() const { return _timestamp; } long filesize() const { return _filesize; } const char* name() const { return _name->data(); } @@ -112,6 +112,7 @@ public: int _version; // (from enum, above.) size_t _alignment; // how shared archive should be aligned int _obj_alignment; // value of ObjectAlignmentInBytes + address _narrow_oop_base; // compressed oop encoding base int _narrow_oop_shift; // compressed oop encoding shift bool _compact_strings; // value of CompactStrings uintx _max_heap_size; // java max heap size during dumping @@ -203,12 +204,13 @@ public: int version() { return _header->_version; } size_t alignment() { return _header->_alignment; } Universe::NARROW_OOP_MODE narrow_oop_mode() { return _header->_narrow_oop_mode; } - int narrow_oop_shift() { return _header->_narrow_oop_shift; } - uintx max_heap_size() { return _header->_max_heap_size; } - address narrow_klass_base() const { return _header->_narrow_klass_base; } + address narrow_oop_base() const { return _header->_narrow_oop_base; } + int narrow_oop_shift() const { return _header->_narrow_oop_shift; } + uintx max_heap_size() const { return _header->_max_heap_size; } + address narrow_klass_base() const { return _header->_narrow_klass_base; } int narrow_klass_shift() const { return _header->_narrow_klass_shift; } - struct FileMapHeader* header() { return _header; } - char* misc_data_patching_start() { return _header->_misc_data_patching_start; } + struct FileMapHeader* header() { return _header; } + char* misc_data_patching_start() { return _header->_misc_data_patching_start; } void set_misc_data_patching_start(char* p) { _header->_misc_data_patching_start = p; } char* read_only_tables_start() { return _header->_read_only_tables_start; } void set_read_only_tables_start(char* p) { _header->_read_only_tables_start = p; } diff --git a/src/hotspot/share/memory/heap.cpp b/src/hotspot/share/memory/heap.cpp index 1b2a35b3c40..09fa63862ec 100644 --- a/src/hotspot/share/memory/heap.cpp +++ b/src/hotspot/share/memory/heap.cpp @@ -222,6 +222,20 @@ void* CodeHeap::allocate(size_t instance_size) { } } +void CodeHeap::deallocate_tail(void* p, size_t used_size) { + assert(p == find_start(p), "illegal deallocation"); + // Find start of HeapBlock + HeapBlock* b = (((HeapBlock *)p) - 1); + assert(b->allocated_space() == p, "sanity check"); + size_t used_number_of_segments = size_to_segments(used_size + header_size()); + size_t actual_number_of_segments = b->length(); + guarantee(used_number_of_segments <= actual_number_of_segments, "Must be!"); + guarantee(b == block_at(_next_segment - actual_number_of_segments), "Intermediate allocation!"); + size_t number_of_segments_to_deallocate = actual_number_of_segments - used_number_of_segments; + _next_segment -= number_of_segments_to_deallocate; + mark_segmap_as_free(_next_segment, _next_segment + number_of_segments_to_deallocate); + b->initialize(used_number_of_segments); +} void CodeHeap::deallocate(void* p) { assert(p == find_start(p), "illegal deallocation"); diff --git a/src/hotspot/share/memory/heap.hpp b/src/hotspot/share/memory/heap.hpp index 1f20dc0ee5b..01e6c47fc13 100644 --- a/src/hotspot/share/memory/heap.hpp +++ b/src/hotspot/share/memory/heap.hpp @@ -147,6 +147,12 @@ class CodeHeap : public CHeapObj { // Memory allocation void* allocate (size_t size); // Allocate 'size' bytes in the code cache or return NULL void deallocate(void* p); // Deallocate memory + // Free the tail of segments allocated by the last call to 'allocate()' which exceed 'used_size'. + // ATTENTION: this is only safe to use if there was no other call to 'allocate()' after + // 'p' was allocated. Only intended for freeing memory which would be otherwise + // wasted after the interpreter generation because we don't know the interpreter size + // beforehand and we also can't easily relocate the interpreter to a new location. + void deallocate_tail(void* p, size_t used_size); // Attributes char* low_boundary() const { return _memory.low_boundary(); } diff --git a/src/hotspot/share/memory/iterator.cpp b/src/hotspot/share/memory/iterator.cpp index 83288217c62..31dbb0e288f 100644 --- a/src/hotspot/share/memory/iterator.cpp +++ b/src/hotspot/share/memory/iterator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -29,17 +29,10 @@ #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" -void KlassToOopClosure::do_klass(Klass* k) { - assert(_oop_closure != NULL, "Not initialized?"); - k->oops_do(_oop_closure); -} +DoNothingClosure do_nothing_cl; void CLDToOopClosure::do_cld(ClassLoaderData* cld) { - cld->oops_do(_oop_closure, &_klass_closure, _must_claim_cld); -} - -void CLDToKlassAndOopClosure::do_cld(ClassLoaderData* cld) { - cld->oops_do(_oop_closure, _klass_closure, _must_claim_cld); + cld->oops_do(_oop_closure, _must_claim_cld); } void ObjectToOopClosure::do_object(oop obj) { diff --git a/src/hotspot/share/memory/iterator.hpp b/src/hotspot/share/memory/iterator.hpp index 11cdc513c84..cdd2dff7016 100644 --- a/src/hotspot/share/memory/iterator.hpp +++ b/src/hotspot/share/memory/iterator.hpp @@ -48,6 +48,13 @@ class OopClosure : public Closure { virtual void do_oop(narrowOop* o) = 0; }; +class DoNothingClosure : public OopClosure { + public: + virtual void do_oop(oop* p) {} + virtual void do_oop(narrowOop* p) {} +}; +extern DoNothingClosure do_nothing_cl; + // ExtendedOopClosure adds extra code to be run during oop iterations. // This is needed by the GC and is extracted to a separate type to not // pollute the OopClosure interface. @@ -138,67 +145,27 @@ class CLDClosure : public Closure { virtual void do_cld(ClassLoaderData* cld) = 0; }; -class KlassToOopClosure : public KlassClosure { - friend class MetadataAwareOopClosure; - friend class MetadataAwareOopsInGenClosure; - - OopClosure* _oop_closure; - - // Used when _oop_closure couldn't be set in an initialization list. - void initialize(OopClosure* oop_closure) { - assert(_oop_closure == NULL, "Should only be called once"); - _oop_closure = oop_closure; - } - - public: - KlassToOopClosure(OopClosure* oop_closure = NULL) : _oop_closure(oop_closure) {} - - virtual void do_klass(Klass* k); -}; class CLDToOopClosure : public CLDClosure { OopClosure* _oop_closure; - KlassToOopClosure _klass_closure; bool _must_claim_cld; public: CLDToOopClosure(OopClosure* oop_closure, bool must_claim_cld = true) : _oop_closure(oop_closure), - _klass_closure(oop_closure), _must_claim_cld(must_claim_cld) {} void do_cld(ClassLoaderData* cld); }; -class CLDToKlassAndOopClosure : public CLDClosure { - friend class G1CollectedHeap; - protected: - OopClosure* _oop_closure; - KlassClosure* _klass_closure; - bool _must_claim_cld; - public: - CLDToKlassAndOopClosure(KlassClosure* klass_closure, - OopClosure* oop_closure, - bool must_claim_cld) : - _oop_closure(oop_closure), - _klass_closure(klass_closure), - _must_claim_cld(must_claim_cld) {} - void do_cld(ClassLoaderData* cld); -}; - // The base class for all concurrent marking closures, // that participates in class unloading. // It's used to proxy through the metadata to the oops defined in them. class MetadataAwareOopClosure: public ExtendedOopClosure { - KlassToOopClosure _klass_closure; public: - MetadataAwareOopClosure() : ExtendedOopClosure() { - _klass_closure.initialize(this); - } - MetadataAwareOopClosure(ReferenceProcessor* rp) : ExtendedOopClosure(rp) { - _klass_closure.initialize(this); - } + MetadataAwareOopClosure() : ExtendedOopClosure() { } + MetadataAwareOopClosure(ReferenceProcessor* rp) : ExtendedOopClosure(rp) { } bool do_metadata_nv() { return true; } virtual bool do_metadata() { return do_metadata_nv(); } diff --git a/src/hotspot/share/memory/iterator.inline.hpp b/src/hotspot/share/memory/iterator.inline.hpp index cf2a1f679ec..7e1d973a26d 100644 --- a/src/hotspot/share/memory/iterator.inline.hpp +++ b/src/hotspot/share/memory/iterator.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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 @@ -37,10 +37,8 @@ #include "utilities/debug.hpp" inline void MetadataAwareOopClosure::do_cld_nv(ClassLoaderData* cld) { - assert(_klass_closure._oop_closure == this, "Must be"); - bool claim = true; // Must claim the class loader data before processing. - cld->oops_do(_klass_closure._oop_closure, &_klass_closure, claim); + cld->oops_do(this, claim); } inline void MetadataAwareOopClosure::do_klass_nv(Klass* k) { diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 4a86e8efcda..9cbe3c07279 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -1291,7 +1291,7 @@ VirtualSpaceList::VirtualSpaceList(ReservedSpace rs) : } size_t VirtualSpaceList::free_bytes() { - return virtual_space_list()->free_words_in_vs() * BytesPerWord; + return current_virtual_space()->free_words_in_vs() * BytesPerWord; } // Allocate another meta virtual space and add it to the list. @@ -1499,7 +1499,7 @@ size_t MetaspaceGC::delta_capacity_until_GC(size_t bytes) { } size_t MetaspaceGC::capacity_until_GC() { - size_t value = (size_t)OrderAccess::load_ptr_acquire(&_capacity_until_GC); + size_t value = OrderAccess::load_acquire(&_capacity_until_GC); assert(value >= MetaspaceSize, "Not initialized properly?"); return value; } @@ -1507,16 +1507,16 @@ size_t MetaspaceGC::capacity_until_GC() { bool MetaspaceGC::inc_capacity_until_GC(size_t v, size_t* new_cap_until_GC, size_t* old_cap_until_GC) { assert_is_aligned(v, Metaspace::commit_alignment()); - size_t capacity_until_GC = (size_t) _capacity_until_GC; - size_t new_value = capacity_until_GC + v; + intptr_t capacity_until_GC = _capacity_until_GC; + intptr_t new_value = capacity_until_GC + v; if (new_value < capacity_until_GC) { // The addition wrapped around, set new_value to aligned max value. new_value = align_down(max_uintx, Metaspace::commit_alignment()); } - intptr_t expected = (intptr_t) capacity_until_GC; - intptr_t actual = Atomic::cmpxchg_ptr((intptr_t) new_value, &_capacity_until_GC, expected); + intptr_t expected = _capacity_until_GC; + intptr_t actual = Atomic::cmpxchg(new_value, &_capacity_until_GC, expected); if (expected != actual) { return false; @@ -1534,7 +1534,7 @@ bool MetaspaceGC::inc_capacity_until_GC(size_t v, size_t* new_cap_until_GC, size size_t MetaspaceGC::dec_capacity_until_GC(size_t v) { assert_is_aligned(v, Metaspace::commit_alignment()); - return (size_t)Atomic::add_ptr(-(intptr_t)v, &_capacity_until_GC); + return (size_t)Atomic::sub((intptr_t)v, &_capacity_until_GC); } void MetaspaceGC::initialize() { @@ -2398,7 +2398,7 @@ void SpaceManager::inc_size_metrics(size_t words) { void SpaceManager::inc_used_metrics(size_t words) { // Add to the per SpaceManager total - Atomic::add_ptr(words, &_allocated_blocks_words); + Atomic::add(words, &_allocated_blocks_words); // Add to the global total MetaspaceAux::inc_used(mdtype(), words); } @@ -2718,7 +2718,7 @@ void SpaceManager::dump(outputStream* const out) const { size_t MetaspaceAux::_capacity_words[] = {0, 0}; -size_t MetaspaceAux::_used_words[] = {0, 0}; +volatile size_t MetaspaceAux::_used_words[] = {0, 0}; size_t MetaspaceAux::free_bytes(Metaspace::MetadataType mdtype) { VirtualSpaceList* list = Metaspace::get_space_list(mdtype); @@ -2753,8 +2753,7 @@ void MetaspaceAux::dec_used(Metaspace::MetadataType mdtype, size_t words) { // sweep which is a concurrent phase. Protection by the expand_lock() // is not enough since allocation is on a per Metaspace basis // and protected by the Metaspace lock. - jlong minus_words = (jlong) - (jlong) words; - Atomic::add_ptr(minus_words, &_used_words[mdtype]); + Atomic::sub(words, &_used_words[mdtype]); } void MetaspaceAux::inc_used(Metaspace::MetadataType mdtype, size_t words) { @@ -2762,7 +2761,7 @@ void MetaspaceAux::inc_used(Metaspace::MetadataType mdtype, size_t words) { // each piece of metadata. Those allocations are // generally done concurrently by different application // threads so must be done atomically. - Atomic::add_ptr(words, &_used_words[mdtype]); + Atomic::add(words, &_used_words[mdtype]); } size_t MetaspaceAux::used_bytes_slow(Metaspace::MetadataType mdtype) { @@ -3103,10 +3102,16 @@ void Metaspace::set_narrow_klass_base_and_shift(address metaspace_base, address Universe::set_narrow_klass_base(lower_base); - if ((uint64_t)(higher_address - lower_base) <= UnscaledClassSpaceMax) { + // CDS uses LogKlassAlignmentInBytes for narrow_klass_shift. See + // MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() for + // how dump time narrow_klass_shift is set. Although, CDS can work + // with zero-shift mode also, to be consistent with AOT it uses + // LogKlassAlignmentInBytes for klass shift so archived java heap objects + // can be used at same time as AOT code. + if (!UseSharedSpaces + && (uint64_t)(higher_address - lower_base) <= UnscaledClassSpaceMax) { Universe::set_narrow_klass_shift(0); } else { - assert(!UseSharedSpaces, "Cannot shift with UseSharedSpaces"); Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes); } AOTLoader::set_narrow_klass_shift(); @@ -3318,6 +3323,24 @@ void Metaspace::ergo_initialize() { CompressedClassSpaceSize = align_down_bounded(CompressedClassSpaceSize, _reserve_alignment); set_compressed_class_space_size(CompressedClassSpaceSize); + + // Initial virtual space size will be calculated at global_initialize() + size_t min_metaspace_sz = + VIRTUALSPACEMULTIPLIER * InitialBootClassLoaderMetaspaceSize; + if (UseCompressedClassPointers) { + if ((min_metaspace_sz + CompressedClassSpaceSize) > MaxMetaspaceSize) { + if (min_metaspace_sz >= MaxMetaspaceSize) { + vm_exit_during_initialization("MaxMetaspaceSize is too small."); + } else { + FLAG_SET_ERGO(size_t, CompressedClassSpaceSize, + MaxMetaspaceSize - min_metaspace_sz); + } + } + } else if (min_metaspace_sz >= MaxMetaspaceSize) { + FLAG_SET_ERGO(size_t, InitialBootClassLoaderMetaspaceSize, + min_metaspace_sz); + } + } void Metaspace::global_initialize() { @@ -3325,50 +3348,25 @@ void Metaspace::global_initialize() { #if INCLUDE_CDS if (DumpSharedSpaces) { - MetaspaceShared::initialize_shared_rs(); + MetaspaceShared::initialize_dumptime_shared_and_meta_spaces(); } else if (UseSharedSpaces) { - // If using shared space, open the file that contains the shared space - // and map in the memory before initializing the rest of metaspace (so - // the addresses don't conflict) - address cds_address = NULL; - FileMapInfo* mapinfo = new FileMapInfo(); - - // Open the shared archive file, read and validate the header. If - // initialization fails, shared spaces [UseSharedSpaces] are - // disabled and the file is closed. - // Map in spaces now also - if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) { - size_t cds_total = MetaspaceShared::core_spaces_size(); - cds_address = (address)mapinfo->header()->region_addr(0); -#ifdef _LP64 - if (using_class_space()) { - char* cds_end = (char*)(cds_address + cds_total); - cds_end = (char *)align_up(cds_end, _reserve_alignment); - // If UseCompressedClassPointers is set then allocate the metaspace area - // above the heap and above the CDS area (if it exists). - allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address); - // map_heap_regions() compares the current narrow oop and klass encodings - // with the archived ones, so it must be done after all encodings are determined. - mapinfo->map_heap_regions(); - } -#endif // _LP64 - } else { - assert(!mapinfo->is_open() && !UseSharedSpaces, - "archive file not closed or shared spaces not disabled."); - } + // If any of the archived space fails to map, UseSharedSpaces + // is reset to false. Fall through to the + // (!DumpSharedSpaces && !UseSharedSpaces) case to set up class + // metaspace. + MetaspaceShared::initialize_runtime_shared_and_meta_spaces(); } -#endif // INCLUDE_CDS + if (!DumpSharedSpaces && !UseSharedSpaces) +#endif // INCLUDE_CDS + { #ifdef _LP64 - if (!UseSharedSpaces && using_class_space()) { - if (DumpSharedSpaces) { - // Already initialized inside MetaspaceShared::initialize_shared_rs() - } else { + if (using_class_space()) { char* base = (char*)align_up(Universe::heap()->reserved_region().end(), _reserve_alignment); allocate_metaspace_compressed_klass_ptrs(base, 0); } - } #endif // _LP64 + } // Initialize these before initializing the VirtualSpaceList _first_chunk_word_size = InitialBootClassLoaderMetaspaceSize / BytesPerWord; diff --git a/src/hotspot/share/memory/metaspace.hpp b/src/hotspot/share/memory/metaspace.hpp index 879388e7f32..bda5190c314 100644 --- a/src/hotspot/share/memory/metaspace.hpp +++ b/src/hotspot/share/memory/metaspace.hpp @@ -179,6 +179,10 @@ class Metaspace : public CHeapObj { assert(DumpSharedSpaces, "sanity"); DEBUG_ONLY(_frozen = true;) } +#ifdef _LP64 + static void allocate_metaspace_compressed_klass_ptrs(char* requested_addr, address cds_base); +#endif + private: #ifdef _LP64 @@ -187,8 +191,6 @@ class Metaspace : public CHeapObj { // Returns true if can use CDS with metaspace allocated as specified address. static bool can_use_cds_with_metaspace_addr(char* metaspace_base, address cds_base); - static void allocate_metaspace_compressed_klass_ptrs(char* requested_addr, address cds_base); - static void initialize_class_space(ReservedSpace rs); #endif size_t class_chunk_size(size_t word_size); @@ -273,7 +275,7 @@ class MetaspaceAux : AllStatic { // Running sum of space in all Metachunks that // are being used for metadata. One for each // type of Metadata. - static size_t _used_words[Metaspace:: MetadataTypeCount]; + static volatile size_t _used_words[Metaspace:: MetadataTypeCount]; public: // Decrement and increment _allocated_capacity_words diff --git a/src/hotspot/share/memory/metaspaceShared.cpp b/src/hotspot/share/memory/metaspaceShared.cpp index eb80850b151..ea92ff79d92 100644 --- a/src/hotspot/share/memory/metaspaceShared.cpp +++ b/src/hotspot/share/memory/metaspaceShared.cpp @@ -157,16 +157,9 @@ public: return !is_packed() && _base != NULL; } - double perc(size_t used, size_t total) const { - if (total == 0) { - total = 1; - } - return used / double(total) * 100.0; - } - void print(size_t total_bytes) const { - tty->print_cr("%s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT, - _name, used(), perc(used(), total_bytes), reserved(), perc(used(), reserved()), p2i(_base)); + tty->print_cr("%-3s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT, + _name, used(), percent_of(used(), total_bytes), reserved(), percent_of(used(), reserved()), p2i(_base)); } void print_out_of_space_msg(const char* failing_region, size_t needed_bytes) { tty->print("[%-8s] " PTR_FORMAT " - " PTR_FORMAT " capacity =%9d, allocated =%9d", @@ -214,7 +207,42 @@ char* MetaspaceShared::read_only_space_alloc(size_t num_bytes) { return _ro_region.allocate(num_bytes); } -void MetaspaceShared::initialize_shared_rs() { +void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { + assert(UseSharedSpaces, "Must be called when UseSharedSpaces is enabled"); + + // If using shared space, open the file that contains the shared space + // and map in the memory before initializing the rest of metaspace (so + // the addresses don't conflict) + address cds_address = NULL; + FileMapInfo* mapinfo = new FileMapInfo(); + + // Open the shared archive file, read and validate the header. If + // initialization fails, shared spaces [UseSharedSpaces] are + // disabled and the file is closed. + // Map in spaces now also + if (mapinfo->initialize() && map_shared_spaces(mapinfo)) { + size_t cds_total = core_spaces_size(); + cds_address = (address)mapinfo->header()->region_addr(0); +#ifdef _LP64 + if (Metaspace::using_class_space()) { + char* cds_end = (char*)(cds_address + cds_total); + cds_end = (char *)align_up(cds_end, Metaspace::reserve_alignment()); + // If UseCompressedClassPointers is set then allocate the metaspace area + // above the heap and above the CDS area (if it exists). + Metaspace::allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address); + // map_heap_regions() compares the current narrow oop and klass encodings + // with the archived ones, so it must be done after all encodings are determined. + mapinfo->map_heap_regions(); + } +#endif // _LP64 + } else { + assert(!mapinfo->is_open() && !UseSharedSpaces, + "archive file not closed or shared spaces not disabled."); + } +} + +void MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() { + assert(DumpSharedSpaces, "should be called for dump time only"); const size_t reserve_alignment = Metaspace::reserve_alignment(); bool large_pages = false; // No large pages when dumping the CDS archive. char* shared_base = (char*)align_up((char*)SharedBaseAddress, reserve_alignment); @@ -223,12 +251,12 @@ void MetaspaceShared::initialize_shared_rs() { // On 64-bit VM, the heap and class space layout will be the same as if // you're running in -Xshare:on mode: // - // +-- SharedBaseAddress (default = 0x800000000) - // v - // +-..---------+----+ ... +----+----+----+----+----+---------------+ - // | Heap | ST | | MC | RW | RO | MD | OD | class space | - // +-..---------+----+ ... +----+----+----+----+----+---------------+ - // |<--MaxHeapSize->| |<-- UnscaledClassSpaceMax = 4GB ------->| + // +-- SharedBaseAddress (default = 0x800000000) + // v + // +-..---------+---------+ ... +----+----+----+----+----+---------------+ + // | Heap | Archive | | MC | RW | RO | MD | OD | class space | + // +-..---------+---------+ ... +----+----+----+----+----+---------------+ + // |<-- MaxHeapSize -->| |<-- UnscaledClassSpaceMax = 4GB ------->| // const uint64_t UnscaledClassSpaceMax = (uint64_t(max_juint) + 1); const size_t cds_total = align_down(UnscaledClassSpaceMax, reserve_alignment); @@ -268,12 +296,9 @@ void MetaspaceShared::initialize_shared_rs() { // Set up compress class pointers. Universe::set_narrow_klass_base((address)_shared_rs.base()); - if (UseAOT || cds_total > UnscaledClassSpaceMax) { - // AOT forces narrow_klass_shift=LogKlassAlignmentInBytes - Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes); - } else { - Universe::set_narrow_klass_shift(0); - } + // Set narrow_klass_shift to be LogKlassAlignmentInBytes. This is consistent + // with AOT. + Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes); Metaspace::initialize_class_space(tmp_class_space); tty->print_cr("narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d", @@ -874,9 +899,9 @@ void DumpAllocStats::print_stats(int ro_all, int rw_all, int mc_all, int md_all) int count = ro_count + rw_count; int bytes = ro_bytes + rw_bytes; - double ro_perc = 100.0 * double(ro_bytes) / double(ro_all); - double rw_perc = 100.0 * double(rw_bytes) / double(rw_all); - double perc = 100.0 * double(bytes) / double(ro_all + rw_all); + double ro_perc = percent_of(ro_bytes, ro_all); + double rw_perc = percent_of(rw_bytes, rw_all); + double perc = percent_of(bytes, ro_all + rw_all); info_stream.print_cr(fmt_stats, name, ro_count, ro_bytes, ro_perc, @@ -892,9 +917,9 @@ void DumpAllocStats::print_stats(int ro_all, int rw_all, int mc_all, int md_all) int all_count = all_ro_count + all_rw_count; int all_bytes = all_ro_bytes + all_rw_bytes; - double all_ro_perc = 100.0 * double(all_ro_bytes) / double(ro_all); - double all_rw_perc = 100.0 * double(all_rw_bytes) / double(rw_all); - double all_perc = 100.0 * double(all_bytes) / double(ro_all + rw_all); + double all_ro_perc = percent_of(all_ro_bytes, ro_all); + double all_rw_perc = percent_of(all_rw_bytes, rw_all); + double all_perc = percent_of(all_bytes, ro_all + rw_all); info_stream.print_cr("%s", sep); info_stream.print_cr(fmt_stats, "Total", @@ -1395,7 +1420,7 @@ void VM_PopulateDumpSharedSpace::print_region_stats() { _od_region.used() + _total_string_region_size + _total_open_archive_region_size; - const double total_u_perc = total_bytes / double(total_reserved) * 100.0; + const double total_u_perc = percent_of(total_bytes, total_reserved); _mc_region.print(total_reserved); _rw_region.print(total_reserved); @@ -1405,7 +1430,7 @@ void VM_PopulateDumpSharedSpace::print_region_stats() { print_heap_region_stats(_string_regions, "st", total_reserved); print_heap_region_stats(_open_archive_heap_regions, "oa", total_reserved); - tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]", + tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]", total_bytes, total_reserved, total_u_perc); } @@ -1416,7 +1441,7 @@ void VM_PopulateDumpSharedSpace::print_heap_region_stats(GrowableArrayat(i).start(); size_t size = heap_mem->at(i).byte_size(); char* top = start + size; - tty->print_cr("%s%d space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [100%% used] at " INTPTR_FORMAT, + tty->print_cr("%s%d space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [100.0%% used] at " INTPTR_FORMAT, name, i, size, size/double(total_size)*100.0, size, p2i(start)); } diff --git a/src/hotspot/share/memory/metaspaceShared.hpp b/src/hotspot/share/memory/metaspaceShared.hpp index d93dea2809d..972b15261e4 100644 --- a/src/hotspot/share/memory/metaspaceShared.hpp +++ b/src/hotspot/share/memory/metaspaceShared.hpp @@ -146,7 +146,8 @@ class MetaspaceShared : AllStatic { static size_t core_spaces_size() { return _core_spaces_size; } - static void initialize_shared_rs() NOT_CDS_RETURN; + static void initialize_dumptime_shared_and_meta_spaces() NOT_CDS_RETURN; + static void initialize_runtime_shared_and_meta_spaces() NOT_CDS_RETURN; // Delta of this object from the bottom of the archive. static uintx object_delta(void* obj) { diff --git a/src/hotspot/share/memory/resourceArea.cpp b/src/hotspot/share/memory/resourceArea.cpp index 767e45ec148..3995e6335db 100644 --- a/src/hotspot/share/memory/resourceArea.cpp +++ b/src/hotspot/share/memory/resourceArea.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -27,6 +27,15 @@ #include "memory/resourceArea.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" +#include "services/memTracker.hpp" + +void ResourceArea::bias_to(MEMFLAGS new_flags) { + if (new_flags != _flags) { + MemTracker::record_arena_free(_flags); + MemTracker::record_new_arena(new_flags); + _flags = new_flags; + } +} //------------------------------ResourceMark----------------------------------- debug_only(int ResourceArea::_warned;) // to suppress multiple warnings diff --git a/src/hotspot/share/memory/resourceArea.hpp b/src/hotspot/share/memory/resourceArea.hpp index 89ad7457314..5fc13ac9243 100644 --- a/src/hotspot/share/memory/resourceArea.hpp +++ b/src/hotspot/share/memory/resourceArea.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -49,11 +49,11 @@ class ResourceArea: public Arena { debug_only(static int _warned;) // to suppress multiple warnings public: - ResourceArea() : Arena(mtThread) { + ResourceArea(MEMFLAGS flags = mtThread) : Arena(flags) { debug_only(_nesting = 0;) } - ResourceArea(size_t init_size) : Arena(mtThread, init_size) { + ResourceArea(size_t init_size, MEMFLAGS flags = mtThread) : Arena(flags, init_size) { debug_only(_nesting = 0;); } @@ -70,7 +70,11 @@ public: return (char*)Amalloc(size, alloc_failmode); } - debug_only(int nesting() const { return _nesting; }); + // Bias this resource area to specific memory type + // (by default, ResourceArea is tagged as mtThread, per-thread general purpose storage) + void bias_to(MEMFLAGS flags); + + debug_only(int nesting() const { return _nesting; }) }; diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 5d3a57b59fe..44a7de64011 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -84,6 +84,7 @@ #include "utilities/preserveException.hpp" #if INCLUDE_ALL_GCS #include "gc/cms/cmsCollectorPolicy.hpp" +#include "gc/cms/cmsHeap.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/parallel/parallelScavengeHeap.hpp" @@ -536,7 +537,7 @@ bool Universe::has_reference_pending_list() { oop Universe::swap_reference_pending_list(oop list) { assert_pll_locked(is_locked); - return (oop)Atomic::xchg_ptr(list, &_reference_pending_list); + return Atomic::xchg(list, &_reference_pending_list); } #undef assert_pll_locked @@ -758,7 +759,7 @@ CollectedHeap* Universe::create_heap() { } else if (UseG1GC) { return Universe::create_heap_with_policy(); } else if (UseConcMarkSweepGC) { - return Universe::create_heap_with_policy(); + return Universe::create_heap_with_policy(); #endif } else if (UseSerialGC) { return Universe::create_heap_with_policy(); @@ -1064,44 +1065,40 @@ bool universe_post_init() { Universe::_vm_exception = InstanceKlass::cast(k)->allocate_instance(CHECK_false); - if (!DumpSharedSpaces) { - // These are the only Java fields that are currently set during shared space dumping. - // We prefer to not handle this generally, so we always reinitialize these detail messages. - Handle msg = java_lang_String::create_from_str("Java heap space", CHECK_false); - java_lang_Throwable::set_message(Universe::_out_of_memory_error_java_heap, msg()); + Handle msg = java_lang_String::create_from_str("Java heap space", CHECK_false); + java_lang_Throwable::set_message(Universe::_out_of_memory_error_java_heap, msg()); - msg = java_lang_String::create_from_str("Metaspace", CHECK_false); - java_lang_Throwable::set_message(Universe::_out_of_memory_error_metaspace, msg()); - msg = java_lang_String::create_from_str("Compressed class space", CHECK_false); - java_lang_Throwable::set_message(Universe::_out_of_memory_error_class_metaspace, msg()); + msg = java_lang_String::create_from_str("Metaspace", CHECK_false); + java_lang_Throwable::set_message(Universe::_out_of_memory_error_metaspace, msg()); + msg = java_lang_String::create_from_str("Compressed class space", CHECK_false); + java_lang_Throwable::set_message(Universe::_out_of_memory_error_class_metaspace, msg()); - msg = java_lang_String::create_from_str("Requested array size exceeds VM limit", CHECK_false); - java_lang_Throwable::set_message(Universe::_out_of_memory_error_array_size, msg()); + msg = java_lang_String::create_from_str("Requested array size exceeds VM limit", CHECK_false); + java_lang_Throwable::set_message(Universe::_out_of_memory_error_array_size, msg()); - msg = java_lang_String::create_from_str("GC overhead limit exceeded", CHECK_false); - java_lang_Throwable::set_message(Universe::_out_of_memory_error_gc_overhead_limit, msg()); + msg = java_lang_String::create_from_str("GC overhead limit exceeded", CHECK_false); + java_lang_Throwable::set_message(Universe::_out_of_memory_error_gc_overhead_limit, msg()); - msg = java_lang_String::create_from_str("Java heap space: failed reallocation of scalar replaced objects", CHECK_false); - java_lang_Throwable::set_message(Universe::_out_of_memory_error_realloc_objects, msg()); + msg = java_lang_String::create_from_str("Java heap space: failed reallocation of scalar replaced objects", CHECK_false); + java_lang_Throwable::set_message(Universe::_out_of_memory_error_realloc_objects, msg()); - msg = java_lang_String::create_from_str("/ by zero", CHECK_false); - java_lang_Throwable::set_message(Universe::_arithmetic_exception_instance, msg()); + msg = java_lang_String::create_from_str("/ by zero", CHECK_false); + java_lang_Throwable::set_message(Universe::_arithmetic_exception_instance, msg()); - // Setup the array of errors that have preallocated backtrace - k = Universe::_out_of_memory_error_java_heap->klass(); - assert(k->name() == vmSymbols::java_lang_OutOfMemoryError(), "should be out of memory error"); - ik = InstanceKlass::cast(k); + // Setup the array of errors that have preallocated backtrace + k = Universe::_out_of_memory_error_java_heap->klass(); + assert(k->name() == vmSymbols::java_lang_OutOfMemoryError(), "should be out of memory error"); + ik = InstanceKlass::cast(k); - int len = (StackTraceInThrowable) ? (int)PreallocatedOutOfMemoryErrorCount : 0; - Universe::_preallocated_out_of_memory_error_array = oopFactory::new_objArray(ik, len, CHECK_false); - for (int i=0; iallocate_instance(CHECK_false); - Handle err_h = Handle(THREAD, err); - java_lang_Throwable::allocate_backtrace(err_h, CHECK_false); - Universe::preallocated_out_of_memory_errors()->obj_at_put(i, err_h()); - } - Universe::_preallocated_out_of_memory_error_avail_count = (jint)len; + int len = (StackTraceInThrowable) ? (int)PreallocatedOutOfMemoryErrorCount : 0; + Universe::_preallocated_out_of_memory_error_array = oopFactory::new_objArray(ik, len, CHECK_false); + for (int i=0; iallocate_instance(CHECK_false); + Handle err_h = Handle(THREAD, err); + java_lang_Throwable::allocate_backtrace(err_h, CHECK_false); + Universe::preallocated_out_of_memory_errors()->obj_at_put(i, err_h()); } + Universe::_preallocated_out_of_memory_error_avail_count = (jint)len; Universe::initialize_known_methods(CHECK_false); diff --git a/src/hotspot/share/metaprogramming/integralConstant.hpp b/src/hotspot/share/metaprogramming/integralConstant.hpp index 585e848cbec..20940be6e9e 100644 --- a/src/hotspot/share/metaprogramming/integralConstant.hpp +++ b/src/hotspot/share/metaprogramming/integralConstant.hpp @@ -44,7 +44,7 @@ // T is an integral type, and is the value_type. // v is an integral constant, and is the value. template -struct IntegralConstant : AllStatic { +struct IntegralConstant VALUE_OBJ_CLASS_SPEC { typedef T value_type; static const value_type value = v; typedef IntegralConstant type; diff --git a/src/hotspot/share/metaprogramming/primitiveConversions.hpp b/src/hotspot/share/metaprogramming/primitiveConversions.hpp index c3482d7c0d1..8041492e9cb 100644 --- a/src/hotspot/share/metaprogramming/primitiveConversions.hpp +++ b/src/hotspot/share/metaprogramming/primitiveConversions.hpp @@ -167,4 +167,24 @@ inline T PrimitiveConversions::cast(U x) { return Cast()(x); } +// jfloat and jdouble translation to integral types + +template<> +struct PrimitiveConversions::Translate : public TrueType { + typedef double Value; + typedef int64_t Decayed; + + static Decayed decay(Value x) { return PrimitiveConversions::cast(x); } + static Value recover(Decayed x) { return PrimitiveConversions::cast(x); } +}; + +template<> +struct PrimitiveConversions::Translate : public TrueType { + typedef float Value; + typedef int32_t Decayed; + + static Decayed decay(Value x) { return PrimitiveConversions::cast(x); } + static Value recover(Decayed x) { return PrimitiveConversions::cast(x); } +}; + #endif // SHARE_VM_METAPROGRAMMING_PRIMITIVECONVERSIONS_HPP diff --git a/src/hotspot/share/oops/arrayKlass.inline.hpp b/src/hotspot/share/oops/arrayKlass.inline.hpp index 43f62915f34..f0a62bfb966 100644 --- a/src/hotspot/share/oops/arrayKlass.inline.hpp +++ b/src/hotspot/share/oops/arrayKlass.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -29,11 +29,11 @@ #include "oops/arrayKlass.hpp" inline Klass* ArrayKlass::higher_dimension_acquire() const { - return (Klass*) OrderAccess::load_ptr_acquire(&_higher_dimension); + return OrderAccess::load_acquire(&_higher_dimension); } inline void ArrayKlass::release_set_higher_dimension(Klass* k) { - OrderAccess::release_store_ptr(&_higher_dimension, k); + OrderAccess::release_store(&_higher_dimension, k); } #endif // SHARE_VM_OOPS_ARRAYKLASS_INLINE_HPP diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index 7e9534baae3..4b8c191b16f 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -135,6 +135,16 @@ objArrayOop ConstantPool::resolved_references() const { return (objArrayOop)_cache->resolved_references(); } +// Called from outside constant pool resolution where a resolved_reference array +// may not be present. +objArrayOop ConstantPool::resolved_references_or_null() const { + if (_cache == NULL) { + return NULL; + } else { + return (objArrayOop)_cache->resolved_references(); + } +} + // Create resolved_references array and mapping array for original cp indexes // The ldc bytecode was rewritten to have the resolved reference array index so need a way // to map it back for resolving and some unlikely miscellaneous uses. @@ -216,7 +226,7 @@ void ConstantPool::klass_at_put(int class_index, int name_index, int resolved_kl symbol_at_put(name_index, name); name->increment_refcount(); Klass** adr = resolved_klasses()->adr_at(resolved_klass_index); - OrderAccess::release_store_ptr((Klass* volatile *)adr, k); + OrderAccess::release_store(adr, k); // The interpreter assumes when the tag is stored, the klass is resolved // and the Klass* non-NULL, so we need hardware store ordering here. @@ -233,7 +243,7 @@ void ConstantPool::klass_at_put(int class_index, Klass* k) { CPKlassSlot kslot = klass_slot_at(class_index); int resolved_klass_index = kslot.resolved_klass_index(); Klass** adr = resolved_klasses()->adr_at(resolved_klass_index); - OrderAccess::release_store_ptr((Klass* volatile *)adr, k); + OrderAccess::release_store(adr, k); // The interpreter assumes when the tag is stored, the klass is resolved // and the Klass* non-NULL, so we need hardware store ordering here. @@ -284,6 +294,28 @@ void ConstantPool::archive_resolved_references(Thread* THREAD) { set_resolved_references(NULL); } } + +void ConstantPool::resolve_class_constants(TRAPS) { + assert(DumpSharedSpaces, "used during dump time only"); + // The _cache may be NULL if the _pool_holder klass fails verification + // at dump time due to missing dependencies. + if (cache() == NULL || reference_map() == NULL) { + return; // nothing to do + } + + constantPoolHandle cp(THREAD, this); + for (int index = 1; index < length(); index++) { // Index 0 is unused + if (tag_at(index).is_string()) { + Symbol* sym = cp->unresolved_string_at(index); + // Look up only. Only resolve references to already interned strings. + oop str = StringTable::lookup(sym); + if (str != NULL) { + int cache_index = cp->cp_to_object_index(index); + cp->string_at_put(index, cache_index, str); + } + } + } +} #endif // CDS support. Create a new resolved_references array. @@ -479,7 +511,7 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which, trace_class_resolution(this_cp, k); } Klass** adr = this_cp->resolved_klasses()->adr_at(resolved_klass_index); - OrderAccess::release_store_ptr((Klass* volatile *)adr, k); + OrderAccess::release_store(adr, k); // The interpreter assumes when the tag is stored, the klass is resolved // and the Klass* stored in _resolved_klasses is non-NULL, so we need // hardware store ordering here. @@ -712,22 +744,6 @@ void ConstantPool::resolve_string_constants_impl(const constantPoolHandle& this_ } } -bool ConstantPool::resolve_class_constants(TRAPS) { - constantPoolHandle cp(THREAD, this); - for (int index = 1; index < length(); index++) { // Index 0 is unused - if (tag_at(index).is_string()) { - Symbol* sym = cp->unresolved_string_at(index); - // Look up only. Only resolve references to already interned strings. - oop str = StringTable::lookup(sym); - if (str != NULL) { - int cache_index = cp->cp_to_object_index(index); - cp->string_at_put(index, cache_index, str); - } - } - } - return true; -} - Symbol* ConstantPool::exception_message(const constantPoolHandle& this_cp, int which, constantTag tag, oop pending_exception) { // Dig out the detailed message to reuse if possible Symbol* message = java_lang_Throwable::detail_message(pending_exception); diff --git a/src/hotspot/share/oops/constantPool.hpp b/src/hotspot/share/oops/constantPool.hpp index 88b772937ce..681935edae5 100644 --- a/src/hotspot/share/oops/constantPool.hpp +++ b/src/hotspot/share/oops/constantPool.hpp @@ -145,7 +145,7 @@ class ConstantPool : public Metadata { assert(is_within_bounds(which), "index out of bounds"); assert(!tag_at(which).is_unresolved_klass() && !tag_at(which).is_unresolved_klass_in_error(), "Corrupted constant pool"); // Uses volatile because the klass slot changes without a lock. - volatile intptr_t adr = (intptr_t)OrderAccess::load_ptr_acquire(obj_at_addr_raw(which)); + intptr_t adr = OrderAccess::load_acquire(obj_at_addr_raw(which)); assert(adr != 0 || which == 0, "cp entry for klass should not be zero"); return CPSlot(adr); } @@ -226,6 +226,7 @@ class ConstantPool : public Metadata { // resolved strings, methodHandles and callsite objects from the constant pool objArrayOop resolved_references() const; + objArrayOop resolved_references_or_null() const; // mapping resolved object array indexes to cp indexes and back. int object_to_cp_index(int index) { return reference_map()->at(index); } int cp_to_object_index(int index); @@ -406,7 +407,7 @@ class ConstantPool : public Metadata { assert(tag_at(kslot.name_index()).is_symbol(), "sanity"); Klass** adr = resolved_klasses()->adr_at(kslot.resolved_klass_index()); - return (Klass*)OrderAccess::load_ptr_acquire(adr); + return OrderAccess::load_acquire(adr); } // RedefineClasses() API support: @@ -716,9 +717,9 @@ class ConstantPool : public Metadata { // CDS support void archive_resolved_references(Thread *THREAD) NOT_CDS_JAVA_HEAP_RETURN; + void resolve_class_constants(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; void remove_unshareable_info(); void restore_unshareable_info(TRAPS); - bool resolve_class_constants(TRAPS); // The ConstantPool vtable is restored by this call when the ConstantPool is // in the shared archive. See patch_klass_vtables() in metaspaceShared.cpp for // all the gory details. SA, dtrace and pstack helpers distinguish metadata @@ -864,11 +865,13 @@ class ConstantPool : public Metadata { static oop resolve_bootstrap_specifier_at_impl(const constantPoolHandle& this_cp, int index, TRAPS); // Exception handling - static void throw_resolution_error(const constantPoolHandle& this_cp, int which, TRAPS); static Symbol* exception_message(const constantPoolHandle& this_cp, int which, constantTag tag, oop pending_exception); static void save_and_throw_exception(const constantPoolHandle& this_cp, int which, constantTag tag, TRAPS); public: + // Exception handling + static void throw_resolution_error(const constantPoolHandle& this_cp, int which, TRAPS); + // Merging ConstantPool* support: bool compare_entry_to(int index1, const constantPoolHandle& cp2, int index2, TRAPS); void copy_cp_to(int start_i, int end_i, const constantPoolHandle& to_cp, int to_i, TRAPS) { diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index 3d59706073c..ff435a6f526 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/resolutionErrors.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/bytecodes.hpp" #include "interpreter/interpreter.hpp" @@ -91,7 +92,7 @@ void ConstantPoolCacheEntry::set_bytecode_1(Bytecodes::Code code) { assert(c == 0 || c == code || code == 0, "update must be consistent"); #endif // Need to flush pending stores here before bytecode is written. - OrderAccess::release_store_ptr(&_indices, _indices | ((u_char)code << bytecode_1_shift)); + OrderAccess::release_store(&_indices, _indices | ((u_char)code << bytecode_1_shift)); } void ConstantPoolCacheEntry::set_bytecode_2(Bytecodes::Code code) { @@ -101,19 +102,17 @@ void ConstantPoolCacheEntry::set_bytecode_2(Bytecodes::Code code) { assert(c == 0 || c == code || code == 0, "update must be consistent"); #endif // Need to flush pending stores here before bytecode is written. - OrderAccess::release_store_ptr(&_indices, _indices | ((u_char)code << bytecode_2_shift)); + OrderAccess::release_store(&_indices, _indices | ((u_char)code << bytecode_2_shift)); } // Sets f1, ordering with previous writes. void ConstantPoolCacheEntry::release_set_f1(Metadata* f1) { assert(f1 != NULL, ""); - OrderAccess::release_store_ptr((HeapWord*) &_f1, f1); + OrderAccess::release_store(&_f1, f1); } -// Sets flags, but only if the value was previously zero. -bool ConstantPoolCacheEntry::init_flags_atomic(intptr_t flags) { - intptr_t result = Atomic::cmpxchg_ptr(flags, &_flags, 0); - return (result == 0); +void ConstantPoolCacheEntry::set_indy_resolution_failed() { + OrderAccess::release_store(&_flags, _flags | (1 << indy_resolution_failed_shift)); } // Note that concurrent update of both bytecodes can leave one of them @@ -154,7 +153,8 @@ void ConstantPoolCacheEntry::set_parameter_size(int value) { // bother trying to update it once it's nonzero but always make // sure that the final parameter size agrees with what was passed. if (_flags == 0) { - Atomic::cmpxchg_ptr((value & parameter_size_mask), &_flags, 0); + intx newflags = (value & parameter_size_mask); + Atomic::cmpxchg(newflags, &_flags, (intx)0); } guarantee(parameter_size() == value, "size must not change: parameter_size=%d, value=%d", parameter_size(), value); @@ -323,6 +323,25 @@ void ConstantPoolCacheEntry::set_method_handle_common(const constantPoolHandle& return; } + if (indy_resolution_failed()) { + // Before we got here, another thread got a LinkageError exception during + // resolution. Ignore our success and throw their exception. + ConstantPoolCache* cpCache = cpool->cache(); + int index = -1; + for (int i = 0; i < cpCache->length(); i++) { + if (cpCache->entry_at(i) == this) { + index = i; + break; + } + } + guarantee(index >= 0, "Didn't find cpCache entry!"); + int encoded_index = ResolutionErrorTable::encode_cpcache_index( + ConstantPool::encode_invokedynamic_index(index)); + Thread* THREAD = Thread::current(); + ConstantPool::throw_resolution_error(cpool, encoded_index, THREAD); + return; + } + const methodHandle adapter = call_info.resolved_method(); const Handle appendix = call_info.resolved_appendix(); const Handle method_type = call_info.resolved_method_type(); @@ -394,6 +413,40 @@ void ConstantPoolCacheEntry::set_method_handle_common(const constantPoolHandle& } } +bool ConstantPoolCacheEntry::save_and_throw_indy_exc( + const constantPoolHandle& cpool, int cpool_index, int index, constantTag tag, TRAPS) { + + assert(HAS_PENDING_EXCEPTION, "No exception got thrown!"); + assert(PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass()), + "No LinkageError exception"); + + // Use the resolved_references() lock for this cpCache entry. + // resolved_references are created for all classes with Invokedynamic, MethodHandle + // or MethodType constant pool cache entries. + objArrayHandle resolved_references(Thread::current(), cpool->resolved_references()); + assert(resolved_references() != NULL, + "a resolved_references array should have been created for this class"); + ObjectLocker ol(resolved_references, THREAD); + + // if f1 is not null or the indy_resolution_failed flag is set then another + // thread either succeeded in resolving the method or got a LinkageError + // exception, before this thread was able to record its failure. So, clear + // this thread's exception and return false so caller can use the earlier + // thread's result. + if (!is_f1_null() || indy_resolution_failed()) { + CLEAR_PENDING_EXCEPTION; + return false; + } + + Symbol* error = PENDING_EXCEPTION->klass()->name(); + Symbol* message = java_lang_Throwable::detail_message(PENDING_EXCEPTION); + assert("message != NULL", "Missing detail message"); + + SystemDictionary::add_resolution_error(cpool, index, error, message); + set_indy_resolution_failed(); + return true; +} + Method* ConstantPoolCacheEntry::method_if_resolved(const constantPoolHandle& cpool) { // Decode the action of set_method and set_interface_call Bytecodes::Code invoke_code = bytecode_1(); diff --git a/src/hotspot/share/oops/cpCache.hpp b/src/hotspot/share/oops/cpCache.hpp index f35b3bb5e87..16670229ec0 100644 --- a/src/hotspot/share/oops/cpCache.hpp +++ b/src/hotspot/share/oops/cpCache.hpp @@ -31,6 +31,7 @@ #include "oops/oopHandle.hpp" #include "runtime/orderAccess.hpp" #include "utilities/align.hpp" +#include "utilities/constantTag.hpp" class PSPromotionManager; @@ -50,8 +51,8 @@ class PSPromotionManager; // _f1 [ entry specific ] metadata ptr (method or klass) // _f2 [ entry specific ] vtable or res_ref index, or vfinal method ptr // _flags [tos|0|F=1|0|0|0|f|v|0 |0000|field_index] (for field entries) -// bit length [ 4 |1| 1 |1|1|1|1|1|1 |-4--|----16-----] -// _flags [tos|0|F=0|M|A|I|f|0|vf|0000|00000|psize] (for method entries) +// bit length [ 4 |1| 1 |1|1|1|1|1|1 |1 |-3-|----16-----] +// _flags [tos|0|F=0|M|A|I|f|0|vf|indy_rf|000|00000|psize] (for method entries) // bit length [ 4 |1| 1 |1|1|1|1|1|1 |-4--|--8--|--8--] // -------------------------------- @@ -71,6 +72,7 @@ class PSPromotionManager; // f = field or method is final // v = field is volatile // vf = virtual but final (method entries only: is_vfinal()) +// indy_rf = call site specifier method resolution failed // // The flags after TosState have the following interpretation: // bit 27: 0 for fields, 1 for methods @@ -136,7 +138,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { private: volatile intx _indices; // constant pool index & rewrite bytecodes - volatile Metadata* _f1; // entry specific metadata field + Metadata* volatile _f1; // entry specific metadata field volatile intx _f2; // entry specific int/metadata field volatile intx _flags; // flags @@ -144,7 +146,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { void set_bytecode_1(Bytecodes::Code code); void set_bytecode_2(Bytecodes::Code code); void set_f1(Metadata* f1) { - Metadata* existing_f1 = (Metadata*)_f1; // read once + Metadata* existing_f1 = _f1; // read once assert(existing_f1 == NULL || existing_f1 == f1, "illegal field change"); _f1 = f1; } @@ -160,7 +162,6 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { } int make_flags(TosState state, int option_bits, int field_index_or_method_params); void set_flags(intx flags) { _flags = flags; } - bool init_flags_atomic(intx flags); void set_field_flags(TosState field_type, int option_bits, int field_index) { assert((field_index & field_index_mask) == field_index, "field_index in range"); set_flags(make_flags(field_type, option_bits | (1 << is_field_entry_shift), field_index)); @@ -169,10 +170,6 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { assert((method_params & parameter_size_mask) == method_params, "method_params in range"); set_flags(make_flags(return_type, option_bits, method_params)); } - bool init_method_flags_atomic(TosState return_type, int option_bits, int method_params) { - assert((method_params & parameter_size_mask) == method_params, "method_params in range"); - return init_flags_atomic(make_flags(return_type, option_bits, method_params)); - } public: // specific bit definitions for the flags field: @@ -190,6 +187,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { is_final_shift = 22, // (f) is the field or method final? is_volatile_shift = 21, // (v) is the field volatile? is_vfinal_shift = 20, // (vf) did the call resolve to a final method? + indy_resolution_failed_shift= 19, // (indy_rf) did call site specifier resolution fail ? // low order bits give field index (for FieldInfo) or method parameter size: field_index_bits = 16, field_index_mask = right_n_bits(field_index_bits), @@ -286,6 +284,13 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { const CallInfo &call_info // Call link information ); + // Return TRUE if resolution failed and this thread got to record the failure + // status. Return FALSE if another thread succeeded or failed in resolving + // the method and recorded the success or failure before this thread had a + // chance to record its failure. + bool save_and_throw_indy_exc(const constantPoolHandle& cpool, int cpool_index, + int index, constantTag tag, TRAPS); + // invokedynamic and invokehandle call sites have two entries in the // resolved references array: // appendix (at index+0) @@ -332,11 +337,11 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { // Accessors int indices() const { return _indices; } - int indices_ord() const { return (intx)OrderAccess::load_ptr_acquire(&_indices); } + int indices_ord() const { return OrderAccess::load_acquire(&_indices); } int constant_pool_index() const { return (indices() & cp_index_mask); } Bytecodes::Code bytecode_1() const { return Bytecodes::cast((indices_ord() >> bytecode_1_shift) & bytecode_1_mask); } Bytecodes::Code bytecode_2() const { return Bytecodes::cast((indices_ord() >> bytecode_2_shift) & bytecode_2_mask); } - Metadata* f1_ord() const { return (Metadata *)OrderAccess::load_ptr_acquire(&_f1); } + Metadata* f1_ord() const { return (Metadata *)OrderAccess::load_acquire(&_f1); } Method* f1_as_method() const { Metadata* f1 = f1_ord(); assert(f1 == NULL || f1->is_method(), ""); return (Method*)f1; } Klass* f1_as_klass() const { Metadata* f1 = f1_ord(); assert(f1 == NULL || f1->is_klass(), ""); return (Klass*)f1; } // Use the accessor f1() to acquire _f1's value. This is needed for @@ -347,12 +352,14 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { bool is_f1_null() const { Metadata* f1 = f1_ord(); return f1 == NULL; } // classifies a CPC entry as unbound int f2_as_index() const { assert(!is_vfinal(), ""); return (int) _f2; } Method* f2_as_vfinal_method() const { assert(is_vfinal(), ""); return (Method*)_f2; } + intx flags_ord() const { return (intx)OrderAccess::load_acquire(&_flags); } int field_index() const { assert(is_field_entry(), ""); return (_flags & field_index_mask); } int parameter_size() const { assert(is_method_entry(), ""); return (_flags & parameter_size_mask); } bool is_volatile() const { return (_flags & (1 << is_volatile_shift)) != 0; } bool is_final() const { return (_flags & (1 << is_final_shift)) != 0; } bool is_forced_virtual() const { return (_flags & (1 << is_forced_virtual_shift)) != 0; } bool is_vfinal() const { return (_flags & (1 << is_vfinal_shift)) != 0; } + bool indy_resolution_failed() const { intx flags = flags_ord(); return (flags & (1 << indy_resolution_failed_shift)) != 0; } bool has_appendix() const { return (!is_f1_null()) && (_flags & (1 << has_appendix_shift)) != 0; } bool has_method_type() const { return (!is_f1_null()) && (_flags & (1 << has_method_type_shift)) != 0; } bool is_method_entry() const { return (_flags & (1 << is_field_entry_shift)) == 0; } @@ -361,6 +368,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { bool is_double() const { return flag_state() == dtos; } TosState flag_state() const { assert((uint)number_of_states <= (uint)tos_state_mask+1, ""); return (TosState)((_flags >> tos_state_shift) & tos_state_mask); } + void set_indy_resolution_failed(); // Code generation support static WordSize size() { diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index f8366d66b50..8da123a5277 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -151,7 +151,7 @@ InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& par nonstatic_oop_map_size(parser.total_oop_map_count()), parser.is_interface(), parser.is_anonymous(), - should_store_fingerprint()); + should_store_fingerprint(parser.is_anonymous())); const Symbol* const class_name = parser.class_name(); assert(class_name != NULL, "invariant"); @@ -285,6 +285,9 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { java_lang_Class::set_klass(java_mirror(), NULL); } + // Also remove mirror from handles + loader_data->remove_handle(_java_mirror); + // Need to take this class off the class loader data list. loader_data->remove_class(this); @@ -1106,16 +1109,15 @@ void InstanceKlass::call_class_initializer(TRAPS) { void InstanceKlass::mask_for(const methodHandle& method, int bci, InterpreterOopMap* entry_for) { // Lazily create the _oop_map_cache at first request - // Lock-free access requires load_ptr_acquire. - OopMapCache* oop_map_cache = - static_cast(OrderAccess::load_ptr_acquire(&_oop_map_cache)); + // Lock-free access requires load_acquire. + OopMapCache* oop_map_cache = OrderAccess::load_acquire(&_oop_map_cache); if (oop_map_cache == NULL) { MutexLocker x(OopMapCacheAlloc_lock); // Check if _oop_map_cache was allocated while we were waiting for this lock if ((oop_map_cache = _oop_map_cache) == NULL) { oop_map_cache = new OopMapCache(); // Ensure _oop_map_cache is stable, since it is examined without a lock - OrderAccess::release_store_ptr(&_oop_map_cache, oop_map_cache); + OrderAccess::release_store(&_oop_map_cache, oop_map_cache); } } // _oop_map_cache is constant after init; lookup below does its own locking. @@ -1669,7 +1671,7 @@ jmethodID InstanceKlass::get_jmethod_id(const methodHandle& method_h) { // transitions from NULL to non-NULL which is safe because we use // release_set_methods_jmethod_ids() to advertise the new cache. // A partially constructed cache should never be seen by a racing - // thread. We also use release_store_ptr() to save a new jmethodID + // thread. We also use release_store() to save a new jmethodID // in the cache so a partially constructed jmethodID should never be // seen either. Cache reads of existing jmethodIDs proceed without a // lock, but cache writes of a new jmethodID requires uniqueness and @@ -1828,7 +1830,7 @@ jmethodID InstanceKlass::get_jmethod_id_fetch_or_update( // The jmethodID cache can be read while unlocked so we have to // make sure the new jmethodID is complete before installing it // in the cache. - OrderAccess::release_store_ptr(&jmeths[idnum+1], id); + OrderAccess::release_store(&jmeths[idnum+1], id); } else { *to_dealloc_id_p = new_id; // save new id for later delete } @@ -1955,7 +1957,7 @@ bool InstanceKlass::supers_have_passed_fingerprint_checks() { return true; } -bool InstanceKlass::should_store_fingerprint() { +bool InstanceKlass::should_store_fingerprint(bool is_anonymous) { #if INCLUDE_AOT // We store the fingerprint into the InstanceKlass only in the following 2 cases: if (CalculateClassFingerprint) { @@ -1966,6 +1968,10 @@ bool InstanceKlass::should_store_fingerprint() { // (2) We are running -Xshare:dump to create a shared archive return true; } + if (UseAOT && is_anonymous) { + // (3) We are using AOT code from a shared library and see an anonymous class + return true; + } #endif // In all other cases we might set the _misc_has_passed_fingerprint_check bit, @@ -3107,7 +3113,7 @@ void InstanceKlass::print_class_load_logging(ClassLoaderData* loader_data, if (cfs != NULL) { if (cfs->source() != NULL) { if (module_name != NULL) { - if (ClassLoader::is_jrt(cfs->source())) { + if (ClassLoader::is_modules_image(cfs->source())) { info_stream.print(" source: jrt:/%s", module_name); } else { info_stream.print(" source: %s", cfs->source()); diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 7bd6122f3aa..15a6b69bcc2 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -731,7 +731,8 @@ class InstanceKlass: public Klass { } bool supers_have_passed_fingerprint_checks(); - static bool should_store_fingerprint(); + static bool should_store_fingerprint(bool is_anonymous); + bool should_store_fingerprint() const { return should_store_fingerprint(is_anonymous()); } bool has_stored_fingerprint() const; uint64_t get_stored_fingerprint() const; void store_fingerprint(uint64_t fingerprint); diff --git a/src/hotspot/share/oops/instanceKlass.inline.hpp b/src/hotspot/share/oops/instanceKlass.inline.hpp index a213272a9e5..9dd46d5ea33 100644 --- a/src/hotspot/share/oops/instanceKlass.inline.hpp +++ b/src/hotspot/share/oops/instanceKlass.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -35,19 +35,19 @@ #include "utilities/macros.hpp" inline Klass* InstanceKlass::array_klasses_acquire() const { - return (Klass*) OrderAccess::load_ptr_acquire(&_array_klasses); + return OrderAccess::load_acquire(&_array_klasses); } inline void InstanceKlass::release_set_array_klasses(Klass* k) { - OrderAccess::release_store_ptr(&_array_klasses, k); + OrderAccess::release_store(&_array_klasses, k); } inline jmethodID* InstanceKlass::methods_jmethod_ids_acquire() const { - return (jmethodID*)OrderAccess::load_ptr_acquire(&_methods_jmethod_ids); + return OrderAccess::load_acquire(&_methods_jmethod_ids); } inline void InstanceKlass::release_set_methods_jmethod_ids(jmethodID* jmeths) { - OrderAccess::release_store_ptr(&_methods_jmethod_ids, jmeths); + OrderAccess::release_store(&_methods_jmethod_ids, jmeths); } // The iteration over the oops in objects is a hot path in the GC code. diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 7d8670f6a06..82c57239c11 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -43,9 +43,16 @@ #include "trace/traceMacros.hpp" #include "utilities/macros.hpp" #include "utilities/stack.inline.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1SATBCardTableModRefBS.hpp" -#endif // INCLUDE_ALL_GCS + +void Klass::set_java_mirror(Handle m) { + assert(!m.is_null(), "New mirror should never be null."); + assert(_java_mirror.resolve() == NULL, "should only be used to initialize mirror"); + _java_mirror = class_loader_data()->add_handle(m); +} + +oop Klass::java_mirror() const { + return _java_mirror.resolve(); +} bool Klass::is_cloneable() const { return _access_flags.is_cloneable_fast() || @@ -441,51 +448,6 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive, bool clean_alive } } -void Klass::klass_update_barrier_set(oop v) { - record_modified_oops(); -} - -// This barrier is used by G1 to remember the old oop values, so -// that we don't forget any objects that were live at the snapshot at -// the beginning. This function is only used when we write oops into Klasses. -void Klass::klass_update_barrier_set_pre(oop* p, oop v) { -#if INCLUDE_ALL_GCS - if (UseG1GC) { - oop obj = *p; - if (obj != NULL) { - G1SATBCardTableModRefBS::enqueue(obj); - } - } -#endif -} - -void Klass::klass_oop_store(oop* p, oop v) { - assert(!Universe::heap()->is_in_reserved((void*)p), "Should store pointer into metadata"); - assert(v == NULL || Universe::heap()->is_in_reserved((void*)v), "Should store pointer to an object"); - - // do the store - if (always_do_update_barrier) { - klass_oop_store((volatile oop*)p, v); - } else { - klass_update_barrier_set_pre(p, v); - *p = v; - klass_update_barrier_set(v); - } -} - -void Klass::klass_oop_store(volatile oop* p, oop v) { - assert(!Universe::heap()->is_in_reserved((void*)p), "Should store pointer into metadata"); - assert(v == NULL || Universe::heap()->is_in_reserved((void*)v), "Should store pointer to an object"); - - klass_update_barrier_set_pre((oop*)p, v); // Cast away volatile. - OrderAccess::release_store_ptr(p, v); - klass_update_barrier_set(v); -} - -void Klass::oops_do(OopClosure* cl) { - cl->do_oop(&_java_mirror); -} - void Klass::metaspace_pointers_do(MetaspaceClosure* it) { if (log_is_enabled(Trace, cds)) { ResourceMark rm; @@ -532,7 +494,8 @@ void Klass::remove_java_mirror() { ResourceMark rm; log_trace(cds, unshareable)("remove java_mirror: %s", external_name()); } - set_java_mirror(NULL); + // Just null out the mirror. The class_loader_data() no longer exists. + _java_mirror = NULL; } void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 5eb4ae201e0..979aaee4fd5 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -30,6 +30,7 @@ #include "memory/memRegion.hpp" #include "oops/metadata.hpp" #include "oops/oop.hpp" +#include "oops/oopHandle.hpp" #include "trace/traceMacros.hpp" #include "utilities/accessFlags.hpp" #include "utilities/macros.hpp" @@ -119,7 +120,7 @@ class Klass : public Metadata { // Ordered list of all primary supertypes Klass* _primary_supers[_primary_super_limit]; // java/lang/Class instance mirroring this class - oop _java_mirror; + OopHandle _java_mirror; // Superclass Klass* _super; // First subclass (NULL if none); _subklass->next_sibling() is next one @@ -148,10 +149,6 @@ class Klass : public Metadata { // vtable length int _vtable_len; - // Remembered sets support for the oops in the klasses. - jbyte _modified_oops; // Card Table Equivalent (YC/CMS support) - jbyte _accumulated_modified_oops; // Mod Union Equivalent (CMS support) - private: // This is an index into FileMapHeader::_classpath_entry_table[], to // associate this class with the JAR file where it's loaded from during @@ -228,13 +225,15 @@ protected: } } - // store an oop into a field of a Klass - void klass_oop_store(oop* p, oop v); - void klass_oop_store(volatile oop* p, oop v); - // java mirror - oop java_mirror() const { return _java_mirror; } - void set_java_mirror(oop m) { klass_oop_store(&_java_mirror, m); } + oop java_mirror() const; + void set_java_mirror(Handle m); + + // Temporary mirror switch used by RedefineClasses + // Both mirrors are on the ClassLoaderData::_handles list already so no + // barriers are needed. + void set_java_mirror_handle(OopHandle mirror) { _java_mirror = mirror; } + OopHandle java_mirror_handle() const { return _java_mirror; } // modifier flags jint modifier_flags() const { return _modifier_flags; } @@ -260,17 +259,6 @@ protected: ClassLoaderData* class_loader_data() const { return _class_loader_data; } void set_class_loader_data(ClassLoaderData* loader_data) { _class_loader_data = loader_data; } - // The Klasses are not placed in the Heap, so the Card Table or - // the Mod Union Table can't be used to mark when klasses have modified oops. - // The CT and MUT bits saves this information for the individual Klasses. - void record_modified_oops() { _modified_oops = 1; } - void clear_modified_oops() { _modified_oops = 0; } - bool has_modified_oops() { return _modified_oops == 1; } - - void accumulate_modified_oops() { if (has_modified_oops()) _accumulated_modified_oops = 1; } - void clear_accumulated_modified_oops() { _accumulated_modified_oops = 0; } - bool has_accumulated_modified_oops() { return _accumulated_modified_oops == 1; } - int shared_classpath_index() const { return _shared_class_path_index; }; @@ -598,9 +586,6 @@ protected: TRACE_DEFINE_TRACE_ID_METHODS; - // garbage collection support - void oops_do(OopClosure* cl); - virtual void metaspace_pointers_do(MetaspaceClosure* iter); virtual MetaspaceObj::Type type() const { return ClassType; } @@ -687,11 +672,6 @@ protected: static Klass* decode_klass_not_null(narrowKlass v); static Klass* decode_klass(narrowKlass v); - - private: - // barriers used by klass_oop_store - void klass_update_barrier_set(oop v); - void klass_update_barrier_set_pre(oop* p, oop v); }; // Helper to convert the oop iterate macro suffixes into bool values that can be used by template functions. diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index bb6966cdfe5..6ebf6988b43 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -479,13 +479,15 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand allocate_new = false; } - if (checkconstraints) { - // Override vtable entry if passes loader constraint check - // if loader constraint checking requested - // No need to visit his super, since he and his super - // have already made any needed loader constraints. - // Since loader constraints are transitive, it is enough - // to link to the first super, and we get all the others. + // Do not check loader constraints for overpass methods because overpass + // methods are created by the jvm to throw exceptions. + if (checkconstraints && !target_method()->is_overpass()) { + // Override vtable entry if passes loader constraint check + // if loader constraint checking requested + // No need to visit his super, since he and his super + // have already made any needed loader constraints. + // Since loader constraints are transitive, it is enough + // to link to the first super, and we get all the others. Handle super_loader(THREAD, super_klass->class_loader()); if (target_loader() != super_loader()) { @@ -495,21 +497,23 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand super_loader, true, CHECK_(false)); if (failed_type_symbol != NULL) { - const char* msg = "loader constraint violation: when resolving " - "overridden method \"%s\" the class loader (instance" - " of %s) of the current class, %s, and its superclass loader " - "(instance of %s), have different Class objects for the type " - "%s used in the signature"; + const char* msg = "loader constraint violation for class %s: when selecting " + "overriding method \"%s\" the class loader (instance of %s) of the " + "selected method's type %s, and the class loader (instance of %s) for its super " + "type %s have different Class objects for the type %s used in the signature"; + char* curr_class = klass->name()->as_C_string(); char* sig = target_method()->name_and_sig_as_C_string(); const char* loader1 = SystemDictionary::loader_name(target_loader()); - char* current = target_klass->name()->as_C_string(); + char* sel_class = target_klass->name()->as_C_string(); const char* loader2 = SystemDictionary::loader_name(super_loader()); + char* super_class = super_klass->name()->as_C_string(); char* failed_type_name = failed_type_symbol->as_C_string(); - size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + - strlen(current) + strlen(loader2) + strlen(failed_type_name); + size_t buflen = strlen(msg) + strlen(curr_class) + strlen(sig) + + strlen(loader1) + strlen(sel_class) + strlen(loader2) + + strlen(super_class) + strlen(failed_type_name); char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen); - jio_snprintf(buf, buflen, msg, sig, loader1, current, loader2, - failed_type_name); + jio_snprintf(buf, buflen, msg, curr_class, sig, loader1, sel_class, loader2, + super_class, failed_type_name); THROW_MSG_(vmSymbols::java_lang_LinkageError(), buf, false); } } @@ -1193,13 +1197,15 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass // to correctly enforce loader constraints for interface method inheritance target = LinkResolver::lookup_instance_method_in_klasses(_klass, m->name(), m->signature(), CHECK); } - if (target == NULL || !target->is_public() || target->is_abstract()) { - // Entry does not resolve. Leave it empty for AbstractMethodError. - if (!(target == NULL) && !target->is_public()) { - // Stuff an IllegalAccessError throwing method in there instead. - itableOffsetEntry::method_entry(_klass, method_table_offset)[m->itable_index()]. - initialize(Universe::throw_illegal_access_error()); - } + if (target == NULL || !target->is_public() || target->is_abstract() || target->is_overpass()) { + assert(target == NULL || !target->is_overpass() || target->is_public(), + "Non-public overpass method!"); + // Entry does not resolve. Leave it empty for AbstractMethodError or other error. + if (!(target == NULL) && !target->is_public()) { + // Stuff an IllegalAccessError throwing method in there instead. + itableOffsetEntry::method_entry(_klass, method_table_offset)[m->itable_index()]. + initialize(Universe::throw_illegal_access_error()); + } } else { // Entry did resolve, check loader constraints before initializing // if checkconstraints requested @@ -1213,24 +1219,24 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass interface_loader, true, CHECK); if (failed_type_symbol != NULL) { - const char* msg = "loader constraint violation in interface " - "itable initialization: when resolving method \"%s\" the class" - " loader (instance of %s) of the current class, %s, " - "and the class loader (instance of %s) for interface " - "%s have different Class objects for the type %s " - "used in the signature"; - char* sig = target()->name_and_sig_as_C_string(); - const char* loader1 = SystemDictionary::loader_name(method_holder_loader()); + const char* msg = "loader constraint violation in interface itable" + " initialization for class %s: when selecting method \"%s\" the" + " class loader (instance of %s) for super interface %s, and the class" + " loader (instance of %s) of the selected method's type, %s have" + " different Class objects for the type %s used in the signature"; char* current = _klass->name()->as_C_string(); - const char* loader2 = SystemDictionary::loader_name(interface_loader()); + char* sig = m->name_and_sig_as_C_string(); + const char* loader1 = SystemDictionary::loader_name(interface_loader()); char* iface = InstanceKlass::cast(interf)->name()->as_C_string(); + const char* loader2 = SystemDictionary::loader_name(method_holder_loader()); + char* mclass = target()->method_holder()->name()->as_C_string(); char* failed_type_name = failed_type_symbol->as_C_string(); - size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + - strlen(current) + strlen(loader2) + strlen(iface) + + size_t buflen = strlen(msg) + strlen(current) + strlen(sig) + + strlen(loader1) + strlen(iface) + strlen(loader2) + strlen(mclass) + strlen(failed_type_name); char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen); - jio_snprintf(buf, buflen, msg, sig, loader1, current, loader2, - iface, failed_type_name); + jio_snprintf(buf, buflen, msg, current, sig, loader1, iface, + loader2, mclass, failed_type_name); THROW_MSG(vmSymbols::java_lang_LinkageError(), buf); } } diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index f58e96de06a..7380fd7b7fb 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -444,6 +444,11 @@ MethodCounters* Method::build_method_counters(Method* m, TRAPS) { return mh->method_counters(); } +bool Method::init_method_counters(MethodCounters* counters) { + // Try to install a pointer to MethodCounters, return true on success. + return Atomic::cmpxchg(counters, &_method_counters, (MethodCounters*)NULL) == NULL; +} + void Method::cleanup_inline_caches() { // The current system doesn't use inline caches in the interpreter // => nothing to do (keep this method around for future use) @@ -1108,8 +1113,8 @@ void Method::restore_unshareable_info(TRAPS) { } } -volatile address Method::from_compiled_entry_no_trampoline() const { - nmethod *code = (nmethod *)OrderAccess::load_ptr_acquire(&_code); +address Method::from_compiled_entry_no_trampoline() const { + CompiledMethod *code = OrderAccess::load_acquire(&_code); if (code) { return code->verified_entry_point(); } else { @@ -1135,7 +1140,7 @@ address Method::verified_code_entry() { // Not inline to avoid circular ref. bool Method::check_code() const { // cached in a register or local. There's a race on the value of the field. - CompiledMethod *code = (CompiledMethod *)OrderAccess::load_ptr_acquire(&_code); + CompiledMethod *code = OrderAccess::load_acquire(&_code); return code == NULL || (code->method() == NULL) || (code->method() == (Method*)this && !code->is_osr_method()); } @@ -1160,15 +1165,11 @@ void Method::set_code(const methodHandle& mh, CompiledMethod *code) { } OrderAccess::storestore(); -#ifdef SHARK - mh->_from_interpreted_entry = code->insts_begin(); -#else //!SHARK mh->_from_compiled_entry = code->verified_entry_point(); OrderAccess::storestore(); // Instantly compiled code can execute. if (!mh->is_method_handle_intrinsic()) mh->_from_interpreted_entry = mh->get_i2c_entry(); -#endif //!SHARK } diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index a4059e08d79..0a7ee37f100 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -136,9 +136,9 @@ class Method : public Metadata { static address make_adapters(const methodHandle& mh, TRAPS); - volatile address from_compiled_entry() const { return (address)OrderAccess::load_ptr_acquire(&_from_compiled_entry); } - volatile address from_compiled_entry_no_trampoline() const; - volatile address from_interpreted_entry() const{ return (address)OrderAccess::load_ptr_acquire(&_from_interpreted_entry); } + address from_compiled_entry() const { return OrderAccess::load_acquire(&_from_compiled_entry); } + address from_compiled_entry_no_trampoline() const; + address from_interpreted_entry() const{ return OrderAccess::load_acquire(&_from_interpreted_entry); } // access flag AccessFlags access_flags() const { return _access_flags; } @@ -337,7 +337,7 @@ class Method : public Metadata { // The store into method must be released. On platforms without // total store order (TSO) the reference may become visible before // the initialization of data otherwise. - OrderAccess::release_store_ptr((volatile void *)&_method_data, data); + OrderAccess::release_store(&_method_data, data); } MethodCounters* method_counters() const { @@ -348,10 +348,7 @@ class Method : public Metadata { _method_counters = NULL; } - bool init_method_counters(MethodCounters* counters) { - // Try to install a pointer to MethodCounters, return true on success. - return Atomic::cmpxchg_ptr(counters, (volatile void*)&_method_counters, NULL) == NULL; - } + bool init_method_counters(MethodCounters* counters); #ifdef TIERED // We are reusing interpreter_invocation_count as a holder for the previous event count! @@ -452,7 +449,7 @@ class Method : public Metadata { // nmethod/verified compiler entry address verified_code_entry(); bool check_code() const; // Not inline to avoid circular ref - CompiledMethod* volatile code() const { assert( check_code(), "" ); return (CompiledMethod *)OrderAccess::load_ptr_acquire(&_code); } + CompiledMethod* volatile code() const { assert( check_code(), "" ); return OrderAccess::load_acquire(&_code); } void clear_code(bool acquire_lock = true); // Clear out any compiled code static void set_code(const methodHandle& mh, CompiledMethod* code); void set_adapter_entry(AdapterHandlerEntry* adapter) { diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index bd344d624ea..b6095fb6f5a 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -202,7 +202,7 @@ public: _cells[index] = value; } void release_set_cell_at(int index, intptr_t value) { - OrderAccess::release_store_ptr(&_cells[index], value); + OrderAccess::release_store(&_cells[index], value); } intptr_t cell_at(int index) const { return _cells[index]; diff --git a/src/hotspot/share/oops/objArrayKlass.cpp b/src/hotspot/share/oops/objArrayKlass.cpp index 0ad38741f5b..f8126d140fa 100644 --- a/src/hotspot/share/oops/objArrayKlass.cpp +++ b/src/hotspot/share/oops/objArrayKlass.cpp @@ -226,8 +226,6 @@ template void ObjArrayKlass::do_copy(arrayOop s, T* src, // For performance reasons, we assume we are that the write barrier we // are using has optimized modes for arrays of references. At least one // of the asserts below will fail if this is not the case. - assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt"); - assert(bs->has_write_ref_array_pre_opt(), "For pre-barrier as well."); if (s == d) { // since source and destination are equal we do not need conversion checks. diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index 3e33fd35d81..948ff52cc4b 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.hpp @@ -66,7 +66,7 @@ template void oop_store(T* p, oop v) { template void oop_store(volatile T* p, oop v) { update_barrier_set_pre((T*)p, v); // cast away volatile - // Used by release_obj_field_put, so use release_store_ptr. + // Used by release_obj_field_put, so use release_store. oopDesc::release_encode_store_heap_oop(p, v); // When using CMS we must mark the card corresponding to p as dirty // with release sematics to prevent that CMS sees the dirty card but @@ -90,7 +90,7 @@ inline void oop_store_raw(HeapWord* addr, oop value) { // We need a separate file to avoid circular references void oopDesc::release_set_mark(markOop m) { - OrderAccess::release_store_ptr(&_mark, m); + OrderAccess::release_store(&_mark, m); } markOop oopDesc::cas_set_mark(markOop new_mark, markOop old_mark) { @@ -124,7 +124,7 @@ Klass* oopDesc::klass_or_null_acquire() const volatile { volatile narrowKlass* xaddr = const_cast(addr); return Klass::decode_klass(OrderAccess::load_acquire(xaddr)); } else { - return (Klass*)OrderAccess::load_ptr_acquire(&_metadata._klass); + return OrderAccess::load_acquire(&_metadata._klass); } } @@ -161,7 +161,7 @@ void oopDesc::release_set_klass(Klass* k) { OrderAccess::release_store(compressed_klass_addr(), Klass::encode_klass_not_null(k)); } else { - OrderAccess::release_store_ptr(klass_addr(), k); + OrderAccess::release_store(klass_addr(), k); } } @@ -361,7 +361,7 @@ void oopDesc::encode_store_heap_oop(narrowOop* p, oop v) { // Store heap oop as is for volatile fields. void oopDesc::release_store_heap_oop(volatile oop* p, oop v) { - OrderAccess::release_store_ptr(p, v); + OrderAccess::release_store(p, v); } void oopDesc::release_store_heap_oop(volatile narrowOop* p, narrowOop v) { OrderAccess::release_store(p, v); @@ -372,11 +372,11 @@ void oopDesc::release_encode_store_heap_oop_not_null(volatile narrowOop* p, oop OrderAccess::release_store(p, encode_heap_oop_not_null(v)); } void oopDesc::release_encode_store_heap_oop_not_null(volatile oop* p, oop v) { - OrderAccess::release_store_ptr(p, v); + OrderAccess::release_store(p, v); } void oopDesc::release_encode_store_heap_oop(volatile oop* p, oop v) { - OrderAccess::release_store_ptr(p, v); + OrderAccess::release_store(p, v); } void oopDesc::release_encode_store_heap_oop(volatile narrowOop* p, oop v) { OrderAccess::release_store(p, encode_heap_oop(v)); @@ -388,11 +388,11 @@ oop oopDesc::atomic_exchange_oop(oop exchange_value, volatile HeapWord *dest) { if (UseCompressedOops) { // encode exchange value from oop to T narrowOop val = encode_heap_oop(exchange_value); - narrowOop old = (narrowOop)Atomic::xchg(val, (narrowOop*)dest); + narrowOop old = Atomic::xchg(val, (narrowOop*)dest); // decode old from T to oop return decode_heap_oop(old); } else { - return (oop)Atomic::xchg_ptr(exchange_value, (oop*)dest); + return Atomic::xchg(exchange_value, (oop*)dest); } } @@ -447,11 +447,11 @@ Metadata* oopDesc::metadata_field(int offset) const { return *metadata void oopDesc::metadata_field_put(int offset, Metadata* value) { *metadata_field_addr(offset) = value; } Metadata* oopDesc::metadata_field_acquire(int offset) const { - return (Metadata*)OrderAccess::load_ptr_acquire(metadata_field_addr(offset)); + return OrderAccess::load_acquire(metadata_field_addr(offset)); } void oopDesc::release_metadata_field_put(int offset, Metadata* value) { - OrderAccess::release_store_ptr(metadata_field_addr(offset), value); + OrderAccess::release_store(metadata_field_addr(offset), value); } jbyte oopDesc::byte_field(int offset) const { return (jbyte) *byte_field_addr(offset); } @@ -485,8 +485,8 @@ oop oopDesc::obj_field_acquire(int offset) const { return UseCompressedOops ? decode_heap_oop((narrowOop) OrderAccess::load_acquire(obj_field_addr(offset))) - : decode_heap_oop((oop) - OrderAccess::load_ptr_acquire(obj_field_addr(offset))); + : decode_heap_oop( + OrderAccess::load_acquire(obj_field_addr(offset))); } void oopDesc::release_obj_field_put(int offset, oop value) { UseCompressedOops ? @@ -501,7 +501,7 @@ jchar oopDesc::char_field_acquire(int offset) const { return O void oopDesc::release_char_field_put(int offset, jchar contents) { OrderAccess::release_store(char_field_addr(offset), contents); } jboolean oopDesc::bool_field_acquire(int offset) const { return OrderAccess::load_acquire(bool_field_addr(offset)); } -void oopDesc::release_bool_field_put(int offset, jboolean contents) { OrderAccess::release_store(bool_field_addr(offset), (contents & 1)); } +void oopDesc::release_bool_field_put(int offset, jboolean contents) { OrderAccess::release_store(bool_field_addr(offset), jboolean(contents & 1)); } jint oopDesc::int_field_acquire(int offset) const { return OrderAccess::load_acquire(int_field_addr(offset)); } void oopDesc::release_int_field_put(int offset, jint contents) { OrderAccess::release_store(int_field_addr(offset), contents); } @@ -518,8 +518,8 @@ void oopDesc::release_float_field_put(int offset, jfloat contents) { OrderAcc jdouble oopDesc::double_field_acquire(int offset) const { return OrderAccess::load_acquire(double_field_addr(offset)); } void oopDesc::release_double_field_put(int offset, jdouble contents) { OrderAccess::release_store(double_field_addr(offset), contents); } -address oopDesc::address_field_acquire(int offset) const { return (address) OrderAccess::load_ptr_acquire(address_field_addr(offset)); } -void oopDesc::release_address_field_put(int offset, address contents) { OrderAccess::release_store_ptr(address_field_addr(offset), contents); } +address oopDesc::address_field_acquire(int offset) const { return OrderAccess::load_acquire(address_field_addr(offset)); } +void oopDesc::release_address_field_put(int offset, address contents) { OrderAccess::release_store(address_field_addr(offset), contents); } bool oopDesc::is_locked() const { return mark()->is_locked(); @@ -539,7 +539,7 @@ bool oopDesc::is_gc_marked() const { } bool oopDesc::is_scavengable() const { - return Universe::heap()->is_scavengable(this); + return Universe::heap()->is_scavengable(oop(const_cast(this))); } // Used by scavengers diff --git a/src/hotspot/share/oops/oopsHierarchy.hpp b/src/hotspot/share/oops/oopsHierarchy.hpp index 36c93c12c13..bbab7d2428d 100644 --- a/src/hotspot/share/oops/oopsHierarchy.hpp +++ b/src/hotspot/share/oops/oopsHierarchy.hpp @@ -177,6 +177,15 @@ struct PrimitiveConversions::Translate : public TrueType { (void)const_cast(oop::operator=(o)); \ return *this; \ } \ + }; \ + \ + template<> \ + struct PrimitiveConversions::Translate : public TrueType { \ + typedef type##Oop Value; \ + typedef type##OopDesc* Decayed; \ + \ + static Decayed decay(Value x) { return (type##OopDesc*)x.obj(); } \ + static Value recover(Decayed x) { return type##Oop(x); } \ }; DEF_OOP(instance); diff --git a/src/hotspot/share/opto/bytecodeInfo.cpp b/src/hotspot/share/opto/bytecodeInfo.cpp index 8071d76b95c..2558c77e0e4 100644 --- a/src/hotspot/share/opto/bytecodeInfo.cpp +++ b/src/hotspot/share/opto/bytecodeInfo.cpp @@ -644,7 +644,8 @@ InlineTree *InlineTree::build_inline_tree_for_callee( ciMethod* callee_method, J C->log()->elem("inline_level_discount caller='%d' callee='%d'", id1, id2); } } - InlineTree* ilt = new InlineTree(C, this, callee_method, caller_jvms, caller_bci, recur_frequency, _max_inline_level + max_inline_level_adjust); + // Allocate in the comp_arena to make sure the InlineTree is live when dumping a replay compilation file + InlineTree* ilt = new (C->comp_arena()) InlineTree(C, this, callee_method, caller_jvms, caller_bci, recur_frequency, _max_inline_level + max_inline_level_adjust); _subtrees.append(ilt); NOT_PRODUCT( _count_inlines += 1; ) diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index febeb5f56f9..e1c859c3af9 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -192,7 +192,7 @@ "of rounds of unroll,optimize,..") \ range(0, max_jint) \ \ - product(bool, UseSubwordForMaxVector, false, \ + product(bool, UseSubwordForMaxVector, true, \ "Use Subword Analysis to set maximum vector size") \ \ develop(intx, UnrollLimitForProfileCheck, 1, \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 9f823784824..7170a0bee93 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -410,6 +410,9 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_multiplyExactL: if (!Matcher::match_rule_supported(Op_OverflowMulL)) return false; break; + case vmIntrinsics::_multiplyHigh: + if (!Matcher::match_rule_supported(Op_MulHiL)) return false; + break; case vmIntrinsics::_getCallerClass: if (SystemDictionary::reflect_CallerSensitive_klass() == NULL) return false; break; diff --git a/src/hotspot/share/opto/chaitin.cpp b/src/hotspot/share/opto/chaitin.cpp index 901f53023a7..914dc43f64f 100644 --- a/src/hotspot/share/opto/chaitin.cpp +++ b/src/hotspot/share/opto/chaitin.cpp @@ -348,8 +348,8 @@ void PhaseChaitin::Register_Allocate() { _alternate = 0; _matcher._allocation_started = true; - ResourceArea split_arena; // Arena for Split local resources - ResourceArea live_arena; // Arena for liveness & IFG info + ResourceArea split_arena(mtCompiler); // Arena for Split local resources + ResourceArea live_arena(mtCompiler); // Arena for liveness & IFG info ResourceMark rm(&live_arena); // Need live-ness for the IFG; need the IFG for coalescing. If the diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index 92cc001f141..50724090270 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -1424,7 +1424,7 @@ void PhaseCFG::global_code_motion() { // Enabling the scheduler for register pressure plus finding blocks of size to schedule for it // is key to enabling this feature. PhaseChaitin regalloc(C->unique(), *this, _matcher, true); - ResourceArea live_arena; // Arena for liveness + ResourceArea live_arena(mtCompiler); // Arena for liveness ResourceMark rm_live(&live_arena); PhaseLive live(*this, regalloc._lrg_map.names(), &live_arena, true); PhaseIFG ifg(&live_arena); diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index f48825b1505..7865e3ca882 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -477,6 +477,9 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) { // if this IfNode follows a range check pattern return the projection // for the failed path ProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) { + if (outcnt() != 2) { + return NULL; + } Node* b = in(1); if (b == NULL || !b->is_Bool()) return NULL; BoolNode* bn = b->as_Bool(); diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index f0fce1d7e48..bb4ed6cef8e 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -231,6 +231,7 @@ class LibraryCallKit : public GraphKit { bool inline_math_addExactL(bool is_increment); bool inline_math_multiplyExactI(); bool inline_math_multiplyExactL(); + bool inline_math_multiplyHigh(); bool inline_math_negateExactI(); bool inline_math_negateExactL(); bool inline_math_subtractExactI(bool is_decrement); @@ -549,6 +550,7 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_incrementExactL: return inline_math_addExactL(true /* increment */); case vmIntrinsics::_multiplyExactI: return inline_math_multiplyExactI(); case vmIntrinsics::_multiplyExactL: return inline_math_multiplyExactL(); + case vmIntrinsics::_multiplyHigh: return inline_math_multiplyHigh(); case vmIntrinsics::_negateExactI: return inline_math_negateExactI(); case vmIntrinsics::_negateExactL: return inline_math_negateExactL(); case vmIntrinsics::_subtractExactI: return inline_math_subtractExactI(false /* subtract */); @@ -1897,6 +1899,11 @@ bool LibraryCallKit::inline_math_multiplyExactL() { return inline_math_overflow(argument(0), argument(2)); } +bool LibraryCallKit::inline_math_multiplyHigh() { + set_result(_gvn.transform(new MulHiLNode(argument(0), argument(2)))); + return true; +} + Node* LibraryCallKit::generate_min_max(vmIntrinsics::ID id, Node* x0, Node* y0) { // These are the candidate return value: @@ -3453,7 +3460,8 @@ bool LibraryCallKit::inline_native_isInterrupted() { // Given a klass oop, load its java mirror (a java.lang.Class oop). Node* LibraryCallKit::load_mirror_from_klass(Node* klass) { Node* p = basic_plus_adr(klass, in_bytes(Klass::java_mirror_offset())); - return make_load(NULL, p, TypeInstPtr::MIRROR, T_OBJECT, MemNode::unordered); + Node* load = make_load(NULL, p, TypeRawPtr::NOTNULL, T_ADDRESS, MemNode::unordered); + return make_load(NULL, load, TypeInstPtr::MIRROR, T_OBJECT, MemNode::unordered); } //-----------------------load_klass_from_mirror_common------------------------- diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index c00dda397db..4737a8ffe9e 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -666,7 +666,7 @@ bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) { _local_loop_unroll_limit = LoopUnrollLimit; _local_loop_unroll_factor = 4; int future_unroll_ct = cl->unrolled_count() * 2; - if (!cl->do_unroll_only()) { + if (!cl->is_vectorized_loop()) { if (future_unroll_ct > LoopMaxUnroll) return false; } else { // obey user constraints on vector mapped loops with additional unrolling applied diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 06818e71e3a..45acc2fcae2 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -311,6 +311,7 @@ Node *PhaseIdealLoop::has_local_phi_input( Node *n ) { } return NULL; } + assert(m->is_Phi() || is_dominator(get_ctrl(m), n_ctrl), "m has strange control"); } return n_ctrl; @@ -615,6 +616,7 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) { // Now replace all Phis with CMOV's Node *cmov_ctrl = iff->in(0); uint flip = (lp->Opcode() == Op_IfTrue); + Node_List wq; while (1) { PhiNode* phi = NULL; for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) { @@ -627,17 +629,21 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) { if (phi == NULL) break; if (PrintOpto && VerifyLoopOptimizations) { tty->print_cr("CMOV"); } // Move speculative ops - for (uint j = 1; j < region->req(); j++) { - Node *proj = region->in(j); - Node *inp = phi->in(j); - if (get_ctrl(inp) == proj) { // Found local op + wq.push(phi); + while (wq.size() > 0) { + Node *n = wq.pop(); + for (uint j = 1; j < n->req(); j++) { + Node* m = n->in(j); + if (m != NULL && !is_dominator(get_ctrl(m), cmov_ctrl)) { #ifndef PRODUCT - if (PrintOpto && VerifyLoopOptimizations) { - tty->print(" speculate: "); - inp->dump(); - } + if (PrintOpto && VerifyLoopOptimizations) { + tty->print(" speculate: "); + m->dump(); + } #endif - set_ctrl(inp, cmov_ctrl); + set_ctrl(m, cmov_ctrl); + wq.push(m); + } } } Node *cmov = CMoveNode::make(cmov_ctrl, iff->in(1), phi->in(1+flip), phi->in(2-flip), _igvn.type(phi)); @@ -820,45 +826,26 @@ void PhaseIdealLoop::try_move_store_after_loop(Node* n) { } } if (mem_ok) { - // Move the Store out of the loop creating clones along - // all paths out of the loop that observe the stored value + // Move the store out of the loop if the LCA of all + // users (except for the phi) is outside the loop. + Node* hook = new Node(1); _igvn.rehash_node_delayed(phi); - int count = phi->replace_edge(n, n->in(MemNode::Memory)); + int count = phi->replace_edge(n, hook); assert(count > 0, "inconsistent phi"); - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - Node* u = n->fast_out(i); - Node* c = get_ctrl(u); - if (u->is_Phi()) { - c = u->in(0)->in(u->find_edge(n)); - } - IdealLoopTree *u_loop = get_loop(c); - assert (!n_loop->is_member(u_loop), "only the phi should have been a use in the loop"); - while(true) { - Node* next_c = find_non_split_ctrl(idom(c)); - if (n_loop->is_member(get_loop(next_c))) { - break; - } - c = next_c; - } - - Node* st = n->clone(); - st->set_req(0, c); - _igvn.register_new_node_with_optimizer(st); - - set_ctrl(st, c); - IdealLoopTree* new_loop = get_loop(c); - assert(new_loop != n_loop, "should be moved out of loop"); - if (new_loop->_child == NULL) new_loop->_body.push(st); - - _igvn.replace_input_of(u, u->find_edge(n), st); - --imax; - --i; + // Compute latest point this store can go + Node* lca = get_late_ctrl(n, get_ctrl(n)); + if (n_loop->is_member(get_loop(lca))) { + // LCA is in the loop - bail out + _igvn.replace_node(hook, n); + return; } + // Move store out of the loop + _igvn.replace_node(hook, n->in(MemNode::Memory)); + _igvn.replace_input_of(n, 0, lca); + set_ctrl_and_loop(n, lca); - assert(n->outcnt() == 0, "all uses should be gone"); - _igvn.replace_input_of(n, MemNode::Memory, C->top()); // Disconnect the phi now. An empty phi can confuse other // optimizations in this pass of loop opts.. if (phi->in(LoopNode::LoopBackControl) == phi) { diff --git a/src/hotspot/share/opto/machnode.hpp b/src/hotspot/share/opto/machnode.hpp index 60bdc9b8768..8bfd1e5b9c8 100644 --- a/src/hotspot/share/opto/machnode.hpp +++ b/src/hotspot/share/opto/machnode.hpp @@ -115,6 +115,18 @@ public: ConditionRegister as_ConditionRegister(PhaseRegAlloc *ra_, const Node *node, int idx) const { return ::as_ConditionRegister(reg(ra_, node, idx)); } + VectorRegister as_VectorRegister(PhaseRegAlloc *ra_, const Node *node) const { + return ::as_VectorRegister(reg(ra_, node)); + } + VectorRegister as_VectorRegister(PhaseRegAlloc *ra_, const Node *node, int idx) const { + return ::as_VectorRegister(reg(ra_, node, idx)); + } + VectorSRegister as_VectorSRegister(PhaseRegAlloc *ra_, const Node *node) const { + return ::as_VectorSRegister(reg(ra_, node)); + } + VectorSRegister as_VectorSRegister(PhaseRegAlloc *ra_, const Node *node, int idx) const { + return ::as_VectorSRegister(reg(ra_, node, idx)); + } #endif virtual intptr_t constant() const; diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index b15875ccce1..19cdfb99584 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -69,7 +69,7 @@ Matcher::Matcher() _register_save_type(register_save_type), _ruleName(ruleName), _allocation_started(false), - _states_arena(Chunk::medium_size), + _states_arena(Chunk::medium_size, mtCompiler), _visited(&_states_arena), _shared(&_states_arena), _dontcare(&_states_arena) { diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 7b6e972c677..77a9d68f88b 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1771,6 +1771,23 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { Opcode() == Op_LoadKlass, "Field accesses must be precise" ); // For klass/static loads, we expect the _type to be precise + } else if (tp->base() == Type::RawPtr && adr->is_Load() && off == 0) { + /* With mirrors being an indirect in the Klass* + * the VM is now using two loads. LoadKlass(LoadP(LoadP(Klass, mirror_offset), zero_offset)) + * The LoadP from the Klass has a RawPtr type (see LibraryCallKit::load_mirror_from_klass). + * + * So check the type and klass of the node before the LoadP. + */ + Node* adr2 = adr->in(MemNode::Address); + const TypeKlassPtr* tkls = phase->type(adr2)->isa_klassptr(); + if (tkls != NULL && !StressReflectiveCode) { + ciKlass* klass = tkls->klass(); + if (klass->is_loaded() && tkls->klass_is_exact() && tkls->offset() == in_bytes(Klass::java_mirror_offset())) { + assert(adr->Opcode() == Op_LoadP, "must load an oop from _java_mirror"); + assert(Opcode() == Op_LoadP, "must load an oop from _java_mirror"); + return TypeInstPtr::make(klass->java_mirror()); + } + } } const TypeKlassPtr *tkls = tp->isa_klassptr(); @@ -1798,12 +1815,6 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { } const Type* aift = load_array_final_field(tkls, klass); if (aift != NULL) return aift; - if (tkls->offset() == in_bytes(Klass::java_mirror_offset())) { - // The field is Klass::_java_mirror. Return its (constant) value. - // (Folds up the 2nd indirection in anObjConstant.getClass().) - assert(Opcode() == Op_LoadP, "must load an oop from _java_mirror"); - return TypeInstPtr::make(klass->java_mirror()); - } } // We can still check if we are loading from the primary_supers array at a @@ -2203,22 +2214,24 @@ Node* LoadNode::klass_identity_common(PhaseGVN* phase) { // This improves reflective code, often making the Class // mirror go completely dead. (Current exception: Class // mirrors may appear in debug info, but we could clean them out by - // introducing a new debug info operator for Klass*.java_mirror). + // introducing a new debug info operator for Klass.java_mirror). + if (toop->isa_instptr() && toop->klass() == phase->C->env()->Class_klass() && offset == java_lang_Class::klass_offset_in_bytes()) { - // We are loading a special hidden field from a Class mirror, - // the field which points to its Klass or ArrayKlass metaobject. if (base->is_Load()) { - Node* adr2 = base->in(MemNode::Address); - const TypeKlassPtr* tkls = phase->type(adr2)->isa_klassptr(); - if (tkls != NULL && !tkls->empty() - && (tkls->klass()->is_instance_klass() || + Node* base2 = base->in(MemNode::Address); + if (base2->is_Load()) { /* direct load of a load which is the oophandle */ + Node* adr2 = base2->in(MemNode::Address); + const TypeKlassPtr* tkls = phase->type(adr2)->isa_klassptr(); + if (tkls != NULL && !tkls->empty() + && (tkls->klass()->is_instance_klass() || tkls->klass()->is_array_klass()) - && adr2->is_AddP() - ) { - int mirror_field = in_bytes(Klass::java_mirror_offset()); - if (tkls->offset() == mirror_field) { - return adr2->in(AddPNode::Base); + && adr2->is_AddP() + ) { + int mirror_field = in_bytes(Klass::java_mirror_offset()); + if (tkls->offset() == mirror_field) { + return adr2->in(AddPNode::Base); + } } } } diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 7f96d6192f7..d7bedfcb396 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1625,6 +1625,17 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) { Node* imem = use->as_Initialize()->proj_out(TypeFunc::Memory); if (imem != NULL) add_users_to_worklist0(imem); } + // Loading the java mirror from a klass oop requires two loads and the type + // of the mirror load depends on the type of 'n'. See LoadNode::Value(). + if (use_op == Op_LoadP && use->bottom_type()->isa_rawptr()) { + for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { + Node* u = use->fast_out(i2); + const Type* ut = u->bottom_type(); + if (u->Opcode() == Op_LoadP && ut->isa_instptr()) { + _worklist.push(u); + } + } + } } } @@ -1760,6 +1771,17 @@ void PhaseCCP::analyze() { worklist.push(phi); } } + // Loading the java mirror from a klass oop requires two loads and the type + // of the mirror load depends on the type of 'n'. See LoadNode::Value(). + if (m_op == Op_LoadP && m->bottom_type()->isa_rawptr()) { + for (DUIterator_Fast i2max, i2 = m->fast_outs(i2max); i2 < i2max; i2++) { + Node* u = m->fast_out(i2); + const Type* ut = u->bottom_type(); + if (u->Opcode() == Op_LoadP && ut->isa_instptr() && ut != type(u)) { + worklist.push(u); + } + } + } } } } diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index a7a5ee71cce..0c1cbfec8f2 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -1658,7 +1658,7 @@ NamedCounter* OptoRuntime::new_named_counter(JVMState* youngest_jvms, NamedCount c->set_next(NULL); head = _named_counters; c->set_next(head); - } while (Atomic::cmpxchg_ptr(c, &_named_counters, head) != head); + } while (Atomic::cmpxchg(c, &_named_counters, head) != head); return c; } diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index aa0c335f2b4..cc1d881f10d 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -877,8 +877,8 @@ const Type *CmpPNode::sub( const Type *t1, const Type *t2 ) const { } static inline Node* isa_java_mirror_load(PhaseGVN* phase, Node* n) { - // Return the klass node for - // LoadP(AddP(foo:Klass, #java_mirror)) + // Return the klass node for (indirect load from OopHandle) + // LoadP(LoadP(AddP(foo:Klass, #java_mirror))) // or NULL if not matching. if (n->Opcode() != Op_LoadP) return NULL; @@ -886,6 +886,10 @@ static inline Node* isa_java_mirror_load(PhaseGVN* phase, Node* n) { if (!tp || tp->klass() != phase->C->env()->Class_klass()) return NULL; Node* adr = n->in(MemNode::Address); + // First load from OopHandle + if (adr->Opcode() != Op_LoadP || !phase->type(adr)->isa_rawptr()) return NULL; + adr = adr->in(MemNode::Address); + intptr_t off = 0; Node* k = AddPNode::Ideal_base_and_offset(adr, phase, off); if (k == NULL) return NULL; diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index bbc30e32b02..b35f9b1da67 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -145,6 +145,8 @@ void SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) { // Skip any loops already optimized by slp if (cl->is_vectorized_loop()) return; + if (cl->do_unroll_only()) return; + if (cl->is_main_loop()) { // Check for pre-loop ending with CountedLoopEnd(Bool(Cmp(x,Opaque1(limit)))) CountedLoopEndNode* pre_end = get_pre_loop_end(cl); @@ -2163,7 +2165,15 @@ void SuperWord::print_loop(bool whole) { //------------------------------output--------------------------- // Convert packs into vector node operations void SuperWord::output() { - if (_packset.length() == 0) return; + CountedLoopNode *cl = lpt()->_head->as_CountedLoop(); + Compile* C = _phase->C; + if (_packset.length() == 0) { + // Instigate more unrolling for optimization when vectorization fails. + C->set_major_progress(); + cl->set_notpassed_slp(); + cl->mark_do_unroll_only(); + return; + } #ifndef PRODUCT if (TraceLoopOpts) { @@ -2172,7 +2182,6 @@ void SuperWord::output() { } #endif - CountedLoopNode *cl = lpt()->_head->as_CountedLoop(); if (cl->is_main_loop()) { // MUST ENSURE main loop's initial value is properly aligned: // (iv_initial_value + min_iv_offset) % vector_width_in_bytes() == 0 @@ -2185,7 +2194,6 @@ void SuperWord::output() { } } - Compile* C = _phase->C; uint max_vlen_in_bytes = 0; uint max_vlen = 0; bool can_process_post_loop = (PostLoopMultiversioning && Matcher::has_predicated_vectors() && cl->is_post_loop()); @@ -4493,4 +4501,3 @@ bool SuperWord::hoist_loads_in_graph() { return true; } - diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index ce199a2abd7..08b56cd3d14 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -67,7 +67,13 @@ const Type::TypeInfo Type::_type_info[Type::lastype] = { { Bad, T_ILLEGAL, "vectorx:", false, 0, relocInfo::none }, // VectorX { Bad, T_ILLEGAL, "vectory:", false, 0, relocInfo::none }, // VectorY { Bad, T_ILLEGAL, "vectorz:", false, 0, relocInfo::none }, // VectorZ -#elif defined(PPC64) || defined(S390) +#elif defined(PPC64) + { Bad, T_ILLEGAL, "vectors:", false, 0, relocInfo::none }, // VectorS + { Bad, T_ILLEGAL, "vectord:", false, Op_RegL, relocInfo::none }, // VectorD + { Bad, T_ILLEGAL, "vectorx:", false, Op_VecX, relocInfo::none }, // VectorX + { Bad, T_ILLEGAL, "vectory:", false, 0, relocInfo::none }, // VectorY + { Bad, T_ILLEGAL, "vectorz:", false, 0, relocInfo::none }, // VectorZ +#elif defined(S390) { Bad, T_ILLEGAL, "vectors:", false, 0, relocInfo::none }, // VectorS { Bad, T_ILLEGAL, "vectord:", false, Op_RegL, relocInfo::none }, // VectorD { Bad, T_ILLEGAL, "vectorx:", false, 0, relocInfo::none }, // VectorX diff --git a/src/hotspot/share/precompiled/precompiled.hpp b/src/hotspot/share/precompiled/precompiled.hpp index a6548eaed9c..f3b26b49dcc 100644 --- a/src/hotspot/share/precompiled/precompiled.hpp +++ b/src/hotspot/share/precompiled/precompiled.hpp @@ -26,6 +26,7 @@ // or if the user passes --disable-precompiled-headers to configure. #ifndef DONT_USE_PRECOMPILED_HEADER +# include "jni.h" # include "asm/assembler.hpp" # include "asm/assembler.inline.hpp" # include "asm/codeBuffer.hpp" @@ -71,7 +72,6 @@ # include "code/debugInfoRec.hpp" # include "code/dependencies.hpp" # include "code/exceptionHandlerTable.hpp" -# include "code/jvmticmlr.h" # include "code/location.hpp" # include "code/nativeInst.hpp" # include "code/nmethod.hpp" @@ -160,7 +160,6 @@ # include "oops/symbol.hpp" # include "oops/typeArrayKlass.hpp" # include "oops/typeArrayOop.hpp" -# include "prims/jni.h" # include "prims/jvm.h" # include "prims/jvmtiExport.hpp" # include "prims/methodHandles.hpp" diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 19910ed4734..b4854477784 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -24,6 +24,7 @@ */ #include "precompiled.hpp" +#include "jni.h" #include "ci/ciReplay.hpp" #include "classfile/altHashing.hpp" #include "classfile/classFileStream.hpp" @@ -51,7 +52,6 @@ #include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" #include "oops/typeArrayOop.hpp" -#include "prims/jni.h" #include "prims/jniCheck.hpp" #include "prims/jniExport.hpp" #include "prims/jniFastGetField.hpp" @@ -92,7 +92,7 @@ #include "jvmci/jvmciRuntime.hpp" #endif -static jint CurrentVersion = JNI_VERSION_9; +static jint CurrentVersion = JNI_VERSION_10; #ifdef _WIN32 extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* ); @@ -396,35 +396,33 @@ JNI_ENTRY(jclass, jni_FindClass(JNIEnv *env, const char *name)) } //%note jni_3 - Handle loader; Handle protection_domain; // Find calling class Klass* k = thread->security_get_caller_class(0); + // default to the system loader when no context + Handle loader(THREAD, SystemDictionary::java_system_loader()); if (k != NULL) { - loader = Handle(THREAD, k->class_loader()); // Special handling to make sure JNI_OnLoad and JNI_OnUnload are executed // in the correct class context. - if (loader.is_null() && + if (k->class_loader() == NULL && k->name() == vmSymbols::java_lang_ClassLoader_NativeLibrary()) { JavaValue result(T_OBJECT); JavaCalls::call_static(&result, k, vmSymbols::getFromClass_name(), vmSymbols::void_class_signature(), - thread); - if (HAS_PENDING_EXCEPTION) { - Handle ex(thread, thread->pending_exception()); - CLEAR_PENDING_EXCEPTION; - THROW_HANDLE_0(ex); - } + CHECK_NULL); + // When invoked from JNI_OnLoad, NativeLibrary::getFromClass returns + // a non-NULL Class object. When invoked from JNI_OnUnload, + // it will return NULL to indicate no context. oop mirror = (oop) result.get_jobject(); - loader = Handle(THREAD, - InstanceKlass::cast(java_lang_Class::as_Klass(mirror))->class_loader()); - protection_domain = Handle(THREAD, - InstanceKlass::cast(java_lang_Class::as_Klass(mirror))->protection_domain()); + if (mirror != NULL) { + Klass* fromClass = java_lang_Class::as_Klass(mirror); + loader = Handle(THREAD, fromClass->class_loader()); + protection_domain = Handle(THREAD, fromClass->protection_domain()); + } + } else { + loader = Handle(THREAD, k->class_loader()); } - } else { - // We call ClassLoader.getSystemClassLoader to obtain the system class loader. - loader = Handle(THREAD, SystemDictionary::java_system_loader()); } TempNewSymbol sym = SymbolTable::new_symbol(name, CHECK_NULL); @@ -3775,7 +3773,7 @@ void copy_jni_function_table(const struct JNINativeInterface_ *new_jni_NativeInt intptr_t *a = (intptr_t *) jni_functions(); intptr_t *b = (intptr_t *) new_jni_NativeInterface; for (uint i=0; i < sizeof(struct JNINativeInterface_)/sizeof(void *); i++) { - Atomic::store_ptr(*b++, a++); + Atomic::store(*b++, a++); } } @@ -3896,11 +3894,11 @@ static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) { #if defined(ZERO) && defined(ASSERT) { jint a = 0xcafebabe; - jint b = Atomic::xchg(0xdeadbeef, &a); + jint b = Atomic::xchg((jint) 0xdeadbeef, &a); void *c = &a; - void *d = Atomic::xchg_ptr(&b, &c); + void *d = Atomic::xchg(&b, &c); assert(a == (jint) 0xdeadbeef && b == (jint) 0xcafebabe, "Atomic::xchg() works"); - assert(c == &b && d == &a, "Atomic::xchg_ptr() works"); + assert(c == &b && d == &a, "Atomic::xchg() works"); } #endif // ZERO && ASSERT diff --git a/src/hotspot/share/prims/jni.h b/src/hotspot/share/prims/jni.h deleted file mode 100644 index d5de88d0dd8..00000000000 --- a/src/hotspot/share/prims/jni.h +++ /dev/null @@ -1,1972 +0,0 @@ -/* - * Copyright (c) 1997, 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. - */ - -/* - * We used part of Netscape's Java Runtime Interface (JRI) as the starting - * point of our design and implementation. - */ - -/****************************************************************************** - * Java Runtime Interface - * Copyright (c) 1996 Netscape Communications Corporation. All rights reserved. - *****************************************************************************/ - -#ifndef _JAVASOFT_JNI_H_ -#define _JAVASOFT_JNI_H_ - -#include -#include - -/* jni_md.h contains the machine-dependent typedefs for jbyte, jint - and jlong */ - -#include "jni_md.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * JNI Types - */ - -#ifndef JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H - -typedef unsigned char jboolean; -typedef unsigned short jchar; -typedef short jshort; -typedef float jfloat; -typedef double jdouble; - -typedef jint jsize; - -#ifdef __cplusplus - -class _jobject {}; -class _jclass : public _jobject {}; -class _jthrowable : public _jobject {}; -class _jstring : public _jobject {}; -class _jarray : public _jobject {}; -class _jbooleanArray : public _jarray {}; -class _jbyteArray : public _jarray {}; -class _jcharArray : public _jarray {}; -class _jshortArray : public _jarray {}; -class _jintArray : public _jarray {}; -class _jlongArray : public _jarray {}; -class _jfloatArray : public _jarray {}; -class _jdoubleArray : public _jarray {}; -class _jobjectArray : public _jarray {}; - -typedef _jobject *jobject; -typedef _jclass *jclass; -typedef _jthrowable *jthrowable; -typedef _jstring *jstring; -typedef _jarray *jarray; -typedef _jbooleanArray *jbooleanArray; -typedef _jbyteArray *jbyteArray; -typedef _jcharArray *jcharArray; -typedef _jshortArray *jshortArray; -typedef _jintArray *jintArray; -typedef _jlongArray *jlongArray; -typedef _jfloatArray *jfloatArray; -typedef _jdoubleArray *jdoubleArray; -typedef _jobjectArray *jobjectArray; - -#else - -struct _jobject; - -typedef struct _jobject *jobject; -typedef jobject jclass; -typedef jobject jthrowable; -typedef jobject jstring; -typedef jobject jarray; -typedef jarray jbooleanArray; -typedef jarray jbyteArray; -typedef jarray jcharArray; -typedef jarray jshortArray; -typedef jarray jintArray; -typedef jarray jlongArray; -typedef jarray jfloatArray; -typedef jarray jdoubleArray; -typedef jarray jobjectArray; - -#endif - -typedef jobject jweak; - -typedef union jvalue { - jboolean z; - jbyte b; - jchar c; - jshort s; - jint i; - jlong j; - jfloat f; - jdouble d; - jobject l; -} jvalue; - -struct _jfieldID; -typedef struct _jfieldID *jfieldID; - -struct _jmethodID; -typedef struct _jmethodID *jmethodID; - -/* Return values from jobjectRefType */ -typedef enum _jobjectType { - JNIInvalidRefType = 0, - JNILocalRefType = 1, - JNIGlobalRefType = 2, - JNIWeakGlobalRefType = 3 -} jobjectRefType; - - -#endif /* JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H */ - -/* - * jboolean constants - */ - -#define JNI_FALSE 0 -#define JNI_TRUE 1 - -/* - * possible return values for JNI functions. - */ - -#define JNI_OK 0 /* success */ -#define JNI_ERR (-1) /* unknown error */ -#define JNI_EDETACHED (-2) /* thread detached from the VM */ -#define JNI_EVERSION (-3) /* JNI version error */ -#define JNI_ENOMEM (-4) /* not enough memory */ -#define JNI_EEXIST (-5) /* VM already created */ -#define JNI_EINVAL (-6) /* invalid arguments */ - -/* - * used in ReleaseScalarArrayElements - */ - -#define JNI_COMMIT 1 -#define JNI_ABORT 2 - -/* - * used in RegisterNatives to describe native method name, signature, - * and function pointer. - */ - -typedef struct { - char *name; - char *signature; - void *fnPtr; -} JNINativeMethod; - -/* - * JNI Native Method Interface. - */ - -struct JNINativeInterface_; - -struct JNIEnv_; - -#ifdef __cplusplus -typedef JNIEnv_ JNIEnv; -#else -typedef const struct JNINativeInterface_ *JNIEnv; -#endif - -/* - * JNI Invocation Interface. - */ - -struct JNIInvokeInterface_; - -struct JavaVM_; - -#ifdef __cplusplus -typedef JavaVM_ JavaVM; -#else -typedef const struct JNIInvokeInterface_ *JavaVM; -#endif - -struct JNINativeInterface_ { - void *reserved0; - void *reserved1; - void *reserved2; - - void *reserved3; - jint (JNICALL *GetVersion)(JNIEnv *env); - - jclass (JNICALL *DefineClass) - (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, - jsize len); - jclass (JNICALL *FindClass) - (JNIEnv *env, const char *name); - - jmethodID (JNICALL *FromReflectedMethod) - (JNIEnv *env, jobject method); - jfieldID (JNICALL *FromReflectedField) - (JNIEnv *env, jobject field); - - jobject (JNICALL *ToReflectedMethod) - (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic); - - jclass (JNICALL *GetSuperclass) - (JNIEnv *env, jclass sub); - jboolean (JNICALL *IsAssignableFrom) - (JNIEnv *env, jclass sub, jclass sup); - - jobject (JNICALL *ToReflectedField) - (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic); - - jint (JNICALL *Throw) - (JNIEnv *env, jthrowable obj); - jint (JNICALL *ThrowNew) - (JNIEnv *env, jclass clazz, const char *msg); - jthrowable (JNICALL *ExceptionOccurred) - (JNIEnv *env); - void (JNICALL *ExceptionDescribe) - (JNIEnv *env); - void (JNICALL *ExceptionClear) - (JNIEnv *env); - void (JNICALL *FatalError) - (JNIEnv *env, const char *msg); - - jint (JNICALL *PushLocalFrame) - (JNIEnv *env, jint capacity); - jobject (JNICALL *PopLocalFrame) - (JNIEnv *env, jobject result); - - jobject (JNICALL *NewGlobalRef) - (JNIEnv *env, jobject lobj); - void (JNICALL *DeleteGlobalRef) - (JNIEnv *env, jobject gref); - void (JNICALL *DeleteLocalRef) - (JNIEnv *env, jobject obj); - jboolean (JNICALL *IsSameObject) - (JNIEnv *env, jobject obj1, jobject obj2); - jobject (JNICALL *NewLocalRef) - (JNIEnv *env, jobject ref); - jint (JNICALL *EnsureLocalCapacity) - (JNIEnv *env, jint capacity); - - jobject (JNICALL *AllocObject) - (JNIEnv *env, jclass clazz); - jobject (JNICALL *NewObject) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jobject (JNICALL *NewObjectV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jobject (JNICALL *NewObjectA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jclass (JNICALL *GetObjectClass) - (JNIEnv *env, jobject obj); - jboolean (JNICALL *IsInstanceOf) - (JNIEnv *env, jobject obj, jclass clazz); - - jmethodID (JNICALL *GetMethodID) - (JNIEnv *env, jclass clazz, const char *name, const char *sig); - - jobject (JNICALL *CallObjectMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jobject (JNICALL *CallObjectMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jobject (JNICALL *CallObjectMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); - - jboolean (JNICALL *CallBooleanMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jboolean (JNICALL *CallBooleanMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jboolean (JNICALL *CallBooleanMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); - - jbyte (JNICALL *CallByteMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jbyte (JNICALL *CallByteMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jbyte (JNICALL *CallByteMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jchar (JNICALL *CallCharMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jchar (JNICALL *CallCharMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jchar (JNICALL *CallCharMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jshort (JNICALL *CallShortMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jshort (JNICALL *CallShortMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jshort (JNICALL *CallShortMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jint (JNICALL *CallIntMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jint (JNICALL *CallIntMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jint (JNICALL *CallIntMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jlong (JNICALL *CallLongMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jlong (JNICALL *CallLongMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jlong (JNICALL *CallLongMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jfloat (JNICALL *CallFloatMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jfloat (JNICALL *CallFloatMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jfloat (JNICALL *CallFloatMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jdouble (JNICALL *CallDoubleMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jdouble (JNICALL *CallDoubleMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jdouble (JNICALL *CallDoubleMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - void (JNICALL *CallVoidMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - void (JNICALL *CallVoidMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - void (JNICALL *CallVoidMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); - - jobject (JNICALL *CallNonvirtualObjectMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jobject (JNICALL *CallNonvirtualObjectMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jobject (JNICALL *CallNonvirtualObjectMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue * args); - - jboolean (JNICALL *CallNonvirtualBooleanMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jboolean (JNICALL *CallNonvirtualBooleanMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jboolean (JNICALL *CallNonvirtualBooleanMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue * args); - - jbyte (JNICALL *CallNonvirtualByteMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jbyte (JNICALL *CallNonvirtualByteMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jbyte (JNICALL *CallNonvirtualByteMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jchar (JNICALL *CallNonvirtualCharMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jchar (JNICALL *CallNonvirtualCharMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jchar (JNICALL *CallNonvirtualCharMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jshort (JNICALL *CallNonvirtualShortMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jshort (JNICALL *CallNonvirtualShortMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jshort (JNICALL *CallNonvirtualShortMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jint (JNICALL *CallNonvirtualIntMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jint (JNICALL *CallNonvirtualIntMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jint (JNICALL *CallNonvirtualIntMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jlong (JNICALL *CallNonvirtualLongMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jlong (JNICALL *CallNonvirtualLongMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jlong (JNICALL *CallNonvirtualLongMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jfloat (JNICALL *CallNonvirtualFloatMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jfloat (JNICALL *CallNonvirtualFloatMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jfloat (JNICALL *CallNonvirtualFloatMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jdouble (JNICALL *CallNonvirtualDoubleMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jdouble (JNICALL *CallNonvirtualDoubleMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jdouble (JNICALL *CallNonvirtualDoubleMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - void (JNICALL *CallNonvirtualVoidMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - void (JNICALL *CallNonvirtualVoidMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - void (JNICALL *CallNonvirtualVoidMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue * args); - - jfieldID (JNICALL *GetFieldID) - (JNIEnv *env, jclass clazz, const char *name, const char *sig); - - jobject (JNICALL *GetObjectField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jboolean (JNICALL *GetBooleanField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jbyte (JNICALL *GetByteField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jchar (JNICALL *GetCharField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jshort (JNICALL *GetShortField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jint (JNICALL *GetIntField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jlong (JNICALL *GetLongField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jfloat (JNICALL *GetFloatField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jdouble (JNICALL *GetDoubleField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - - void (JNICALL *SetObjectField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val); - void (JNICALL *SetBooleanField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val); - void (JNICALL *SetByteField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val); - void (JNICALL *SetCharField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val); - void (JNICALL *SetShortField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val); - void (JNICALL *SetIntField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jint val); - void (JNICALL *SetLongField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val); - void (JNICALL *SetFloatField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val); - void (JNICALL *SetDoubleField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val); - - jmethodID (JNICALL *GetStaticMethodID) - (JNIEnv *env, jclass clazz, const char *name, const char *sig); - - jobject (JNICALL *CallStaticObjectMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jobject (JNICALL *CallStaticObjectMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jobject (JNICALL *CallStaticObjectMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jboolean (JNICALL *CallStaticBooleanMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jboolean (JNICALL *CallStaticBooleanMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jboolean (JNICALL *CallStaticBooleanMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jbyte (JNICALL *CallStaticByteMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jbyte (JNICALL *CallStaticByteMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jbyte (JNICALL *CallStaticByteMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jchar (JNICALL *CallStaticCharMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jchar (JNICALL *CallStaticCharMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jchar (JNICALL *CallStaticCharMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jshort (JNICALL *CallStaticShortMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jshort (JNICALL *CallStaticShortMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jshort (JNICALL *CallStaticShortMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jint (JNICALL *CallStaticIntMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jint (JNICALL *CallStaticIntMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jint (JNICALL *CallStaticIntMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jlong (JNICALL *CallStaticLongMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jlong (JNICALL *CallStaticLongMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jlong (JNICALL *CallStaticLongMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jfloat (JNICALL *CallStaticFloatMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jfloat (JNICALL *CallStaticFloatMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jfloat (JNICALL *CallStaticFloatMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jdouble (JNICALL *CallStaticDoubleMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jdouble (JNICALL *CallStaticDoubleMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jdouble (JNICALL *CallStaticDoubleMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - void (JNICALL *CallStaticVoidMethod) - (JNIEnv *env, jclass cls, jmethodID methodID, ...); - void (JNICALL *CallStaticVoidMethodV) - (JNIEnv *env, jclass cls, jmethodID methodID, va_list args); - void (JNICALL *CallStaticVoidMethodA) - (JNIEnv *env, jclass cls, jmethodID methodID, const jvalue * args); - - jfieldID (JNICALL *GetStaticFieldID) - (JNIEnv *env, jclass clazz, const char *name, const char *sig); - jobject (JNICALL *GetStaticObjectField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jboolean (JNICALL *GetStaticBooleanField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jbyte (JNICALL *GetStaticByteField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jchar (JNICALL *GetStaticCharField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jshort (JNICALL *GetStaticShortField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jint (JNICALL *GetStaticIntField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jlong (JNICALL *GetStaticLongField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jfloat (JNICALL *GetStaticFloatField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jdouble (JNICALL *GetStaticDoubleField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - - void (JNICALL *SetStaticObjectField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value); - void (JNICALL *SetStaticBooleanField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value); - void (JNICALL *SetStaticByteField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value); - void (JNICALL *SetStaticCharField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value); - void (JNICALL *SetStaticShortField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value); - void (JNICALL *SetStaticIntField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value); - void (JNICALL *SetStaticLongField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value); - void (JNICALL *SetStaticFloatField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value); - void (JNICALL *SetStaticDoubleField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value); - - jstring (JNICALL *NewString) - (JNIEnv *env, const jchar *unicode, jsize len); - jsize (JNICALL *GetStringLength) - (JNIEnv *env, jstring str); - const jchar *(JNICALL *GetStringChars) - (JNIEnv *env, jstring str, jboolean *isCopy); - void (JNICALL *ReleaseStringChars) - (JNIEnv *env, jstring str, const jchar *chars); - - jstring (JNICALL *NewStringUTF) - (JNIEnv *env, const char *utf); - jsize (JNICALL *GetStringUTFLength) - (JNIEnv *env, jstring str); - const char* (JNICALL *GetStringUTFChars) - (JNIEnv *env, jstring str, jboolean *isCopy); - void (JNICALL *ReleaseStringUTFChars) - (JNIEnv *env, jstring str, const char* chars); - - - jsize (JNICALL *GetArrayLength) - (JNIEnv *env, jarray array); - - jobjectArray (JNICALL *NewObjectArray) - (JNIEnv *env, jsize len, jclass clazz, jobject init); - jobject (JNICALL *GetObjectArrayElement) - (JNIEnv *env, jobjectArray array, jsize index); - void (JNICALL *SetObjectArrayElement) - (JNIEnv *env, jobjectArray array, jsize index, jobject val); - - jbooleanArray (JNICALL *NewBooleanArray) - (JNIEnv *env, jsize len); - jbyteArray (JNICALL *NewByteArray) - (JNIEnv *env, jsize len); - jcharArray (JNICALL *NewCharArray) - (JNIEnv *env, jsize len); - jshortArray (JNICALL *NewShortArray) - (JNIEnv *env, jsize len); - jintArray (JNICALL *NewIntArray) - (JNIEnv *env, jsize len); - jlongArray (JNICALL *NewLongArray) - (JNIEnv *env, jsize len); - jfloatArray (JNICALL *NewFloatArray) - (JNIEnv *env, jsize len); - jdoubleArray (JNICALL *NewDoubleArray) - (JNIEnv *env, jsize len); - - jboolean * (JNICALL *GetBooleanArrayElements) - (JNIEnv *env, jbooleanArray array, jboolean *isCopy); - jbyte * (JNICALL *GetByteArrayElements) - (JNIEnv *env, jbyteArray array, jboolean *isCopy); - jchar * (JNICALL *GetCharArrayElements) - (JNIEnv *env, jcharArray array, jboolean *isCopy); - jshort * (JNICALL *GetShortArrayElements) - (JNIEnv *env, jshortArray array, jboolean *isCopy); - jint * (JNICALL *GetIntArrayElements) - (JNIEnv *env, jintArray array, jboolean *isCopy); - jlong * (JNICALL *GetLongArrayElements) - (JNIEnv *env, jlongArray array, jboolean *isCopy); - jfloat * (JNICALL *GetFloatArrayElements) - (JNIEnv *env, jfloatArray array, jboolean *isCopy); - jdouble * (JNICALL *GetDoubleArrayElements) - (JNIEnv *env, jdoubleArray array, jboolean *isCopy); - - void (JNICALL *ReleaseBooleanArrayElements) - (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode); - void (JNICALL *ReleaseByteArrayElements) - (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode); - void (JNICALL *ReleaseCharArrayElements) - (JNIEnv *env, jcharArray array, jchar *elems, jint mode); - void (JNICALL *ReleaseShortArrayElements) - (JNIEnv *env, jshortArray array, jshort *elems, jint mode); - void (JNICALL *ReleaseIntArrayElements) - (JNIEnv *env, jintArray array, jint *elems, jint mode); - void (JNICALL *ReleaseLongArrayElements) - (JNIEnv *env, jlongArray array, jlong *elems, jint mode); - void (JNICALL *ReleaseFloatArrayElements) - (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode); - void (JNICALL *ReleaseDoubleArrayElements) - (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode); - - void (JNICALL *GetBooleanArrayRegion) - (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf); - void (JNICALL *GetByteArrayRegion) - (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf); - void (JNICALL *GetCharArrayRegion) - (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf); - void (JNICALL *GetShortArrayRegion) - (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf); - void (JNICALL *GetIntArrayRegion) - (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf); - void (JNICALL *GetLongArrayRegion) - (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf); - void (JNICALL *GetFloatArrayRegion) - (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf); - void (JNICALL *GetDoubleArrayRegion) - (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf); - - void (JNICALL *SetBooleanArrayRegion) - (JNIEnv *env, jbooleanArray array, jsize start, jsize l, const jboolean *buf); - void (JNICALL *SetByteArrayRegion) - (JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf); - void (JNICALL *SetCharArrayRegion) - (JNIEnv *env, jcharArray array, jsize start, jsize len, const jchar *buf); - void (JNICALL *SetShortArrayRegion) - (JNIEnv *env, jshortArray array, jsize start, jsize len, const jshort *buf); - void (JNICALL *SetIntArrayRegion) - (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf); - void (JNICALL *SetLongArrayRegion) - (JNIEnv *env, jlongArray array, jsize start, jsize len, const jlong *buf); - void (JNICALL *SetFloatArrayRegion) - (JNIEnv *env, jfloatArray array, jsize start, jsize len, const jfloat *buf); - void (JNICALL *SetDoubleArrayRegion) - (JNIEnv *env, jdoubleArray array, jsize start, jsize len, const jdouble *buf); - - jint (JNICALL *RegisterNatives) - (JNIEnv *env, jclass clazz, const JNINativeMethod *methods, - jint nMethods); - jint (JNICALL *UnregisterNatives) - (JNIEnv *env, jclass clazz); - - jint (JNICALL *MonitorEnter) - (JNIEnv *env, jobject obj); - jint (JNICALL *MonitorExit) - (JNIEnv *env, jobject obj); - - jint (JNICALL *GetJavaVM) - (JNIEnv *env, JavaVM **vm); - - void (JNICALL *GetStringRegion) - (JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf); - void (JNICALL *GetStringUTFRegion) - (JNIEnv *env, jstring str, jsize start, jsize len, char *buf); - - void * (JNICALL *GetPrimitiveArrayCritical) - (JNIEnv *env, jarray array, jboolean *isCopy); - void (JNICALL *ReleasePrimitiveArrayCritical) - (JNIEnv *env, jarray array, void *carray, jint mode); - - const jchar * (JNICALL *GetStringCritical) - (JNIEnv *env, jstring string, jboolean *isCopy); - void (JNICALL *ReleaseStringCritical) - (JNIEnv *env, jstring string, const jchar *cstring); - - jweak (JNICALL *NewWeakGlobalRef) - (JNIEnv *env, jobject obj); - void (JNICALL *DeleteWeakGlobalRef) - (JNIEnv *env, jweak ref); - - jboolean (JNICALL *ExceptionCheck) - (JNIEnv *env); - - jobject (JNICALL *NewDirectByteBuffer) - (JNIEnv* env, void* address, jlong capacity); - void* (JNICALL *GetDirectBufferAddress) - (JNIEnv* env, jobject buf); - jlong (JNICALL *GetDirectBufferCapacity) - (JNIEnv* env, jobject buf); - - /* New JNI 1.6 Features */ - - jobjectRefType (JNICALL *GetObjectRefType) - (JNIEnv* env, jobject obj); - - /* Module Features */ - - jobject (JNICALL *GetModule) - (JNIEnv* env, jclass clazz); -}; - -/* - * We use inlined functions for C++ so that programmers can write: - * - * env->FindClass("java/lang/String") - * - * in C++ rather than: - * - * (*env)->FindClass(env, "java/lang/String") - * - * in C. - */ - -struct JNIEnv_ { - const struct JNINativeInterface_ *functions; -#ifdef __cplusplus - - jint GetVersion() { - return functions->GetVersion(this); - } - jclass DefineClass(const char *name, jobject loader, const jbyte *buf, - jsize len) { - return functions->DefineClass(this, name, loader, buf, len); - } - jclass FindClass(const char *name) { - return functions->FindClass(this, name); - } - jmethodID FromReflectedMethod(jobject method) { - return functions->FromReflectedMethod(this,method); - } - jfieldID FromReflectedField(jobject field) { - return functions->FromReflectedField(this,field); - } - - jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) { - return functions->ToReflectedMethod(this, cls, methodID, isStatic); - } - - jclass GetSuperclass(jclass sub) { - return functions->GetSuperclass(this, sub); - } - jboolean IsAssignableFrom(jclass sub, jclass sup) { - return functions->IsAssignableFrom(this, sub, sup); - } - - jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic) { - return functions->ToReflectedField(this,cls,fieldID,isStatic); - } - - jint Throw(jthrowable obj) { - return functions->Throw(this, obj); - } - jint ThrowNew(jclass clazz, const char *msg) { - return functions->ThrowNew(this, clazz, msg); - } - jthrowable ExceptionOccurred() { - return functions->ExceptionOccurred(this); - } - void ExceptionDescribe() { - functions->ExceptionDescribe(this); - } - void ExceptionClear() { - functions->ExceptionClear(this); - } - void FatalError(const char *msg) { - functions->FatalError(this, msg); - } - - jint PushLocalFrame(jint capacity) { - return functions->PushLocalFrame(this,capacity); - } - jobject PopLocalFrame(jobject result) { - return functions->PopLocalFrame(this,result); - } - - jobject NewGlobalRef(jobject lobj) { - return functions->NewGlobalRef(this,lobj); - } - void DeleteGlobalRef(jobject gref) { - functions->DeleteGlobalRef(this,gref); - } - void DeleteLocalRef(jobject obj) { - functions->DeleteLocalRef(this, obj); - } - - jboolean IsSameObject(jobject obj1, jobject obj2) { - return functions->IsSameObject(this,obj1,obj2); - } - - jobject NewLocalRef(jobject ref) { - return functions->NewLocalRef(this,ref); - } - jint EnsureLocalCapacity(jint capacity) { - return functions->EnsureLocalCapacity(this,capacity); - } - - jobject AllocObject(jclass clazz) { - return functions->AllocObject(this,clazz); - } - jobject NewObject(jclass clazz, jmethodID methodID, ...) { - va_list args; - jobject result; - va_start(args, methodID); - result = functions->NewObjectV(this,clazz,methodID,args); - va_end(args); - return result; - } - jobject NewObjectV(jclass clazz, jmethodID methodID, - va_list args) { - return functions->NewObjectV(this,clazz,methodID,args); - } - jobject NewObjectA(jclass clazz, jmethodID methodID, - const jvalue *args) { - return functions->NewObjectA(this,clazz,methodID,args); - } - - jclass GetObjectClass(jobject obj) { - return functions->GetObjectClass(this,obj); - } - jboolean IsInstanceOf(jobject obj, jclass clazz) { - return functions->IsInstanceOf(this,obj,clazz); - } - - jmethodID GetMethodID(jclass clazz, const char *name, - const char *sig) { - return functions->GetMethodID(this,clazz,name,sig); - } - - jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jobject result; - va_start(args,methodID); - result = functions->CallObjectMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jobject CallObjectMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallObjectMethodV(this,obj,methodID,args); - } - jobject CallObjectMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallObjectMethodA(this,obj,methodID,args); - } - - jboolean CallBooleanMethod(jobject obj, - jmethodID methodID, ...) { - va_list args; - jboolean result; - va_start(args,methodID); - result = functions->CallBooleanMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jboolean CallBooleanMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallBooleanMethodV(this,obj,methodID,args); - } - jboolean CallBooleanMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallBooleanMethodA(this,obj,methodID, args); - } - - jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jbyte result; - va_start(args,methodID); - result = functions->CallByteMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jbyte CallByteMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallByteMethodV(this,obj,methodID,args); - } - jbyte CallByteMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallByteMethodA(this,obj,methodID,args); - } - - jchar CallCharMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jchar result; - va_start(args,methodID); - result = functions->CallCharMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jchar CallCharMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallCharMethodV(this,obj,methodID,args); - } - jchar CallCharMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallCharMethodA(this,obj,methodID,args); - } - - jshort CallShortMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jshort result; - va_start(args,methodID); - result = functions->CallShortMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jshort CallShortMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallShortMethodV(this,obj,methodID,args); - } - jshort CallShortMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallShortMethodA(this,obj,methodID,args); - } - - jint CallIntMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jint result; - va_start(args,methodID); - result = functions->CallIntMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jint CallIntMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallIntMethodV(this,obj,methodID,args); - } - jint CallIntMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallIntMethodA(this,obj,methodID,args); - } - - jlong CallLongMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jlong result; - va_start(args,methodID); - result = functions->CallLongMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jlong CallLongMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallLongMethodV(this,obj,methodID,args); - } - jlong CallLongMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallLongMethodA(this,obj,methodID,args); - } - - jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jfloat result; - va_start(args,methodID); - result = functions->CallFloatMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jfloat CallFloatMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallFloatMethodV(this,obj,methodID,args); - } - jfloat CallFloatMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallFloatMethodA(this,obj,methodID,args); - } - - jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jdouble result; - va_start(args,methodID); - result = functions->CallDoubleMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jdouble CallDoubleMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallDoubleMethodV(this,obj,methodID,args); - } - jdouble CallDoubleMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallDoubleMethodA(this,obj,methodID,args); - } - - void CallVoidMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - va_start(args,methodID); - functions->CallVoidMethodV(this,obj,methodID,args); - va_end(args); - } - void CallVoidMethodV(jobject obj, jmethodID methodID, - va_list args) { - functions->CallVoidMethodV(this,obj,methodID,args); - } - void CallVoidMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - functions->CallVoidMethodA(this,obj,methodID,args); - } - - jobject CallNonvirtualObjectMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jobject result; - va_start(args,methodID); - result = functions->CallNonvirtualObjectMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jobject CallNonvirtualObjectMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualObjectMethodV(this,obj,clazz, - methodID,args); - } - jobject CallNonvirtualObjectMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualObjectMethodA(this,obj,clazz, - methodID,args); - } - - jboolean CallNonvirtualBooleanMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jboolean result; - va_start(args,methodID); - result = functions->CallNonvirtualBooleanMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jboolean CallNonvirtualBooleanMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualBooleanMethodV(this,obj,clazz, - methodID,args); - } - jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualBooleanMethodA(this,obj,clazz, - methodID, args); - } - - jbyte CallNonvirtualByteMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jbyte result; - va_start(args,methodID); - result = functions->CallNonvirtualByteMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jbyte CallNonvirtualByteMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualByteMethodV(this,obj,clazz, - methodID,args); - } - jbyte CallNonvirtualByteMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualByteMethodA(this,obj,clazz, - methodID,args); - } - - jchar CallNonvirtualCharMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jchar result; - va_start(args,methodID); - result = functions->CallNonvirtualCharMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jchar CallNonvirtualCharMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualCharMethodV(this,obj,clazz, - methodID,args); - } - jchar CallNonvirtualCharMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualCharMethodA(this,obj,clazz, - methodID,args); - } - - jshort CallNonvirtualShortMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jshort result; - va_start(args,methodID); - result = functions->CallNonvirtualShortMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jshort CallNonvirtualShortMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualShortMethodV(this,obj,clazz, - methodID,args); - } - jshort CallNonvirtualShortMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualShortMethodA(this,obj,clazz, - methodID,args); - } - - jint CallNonvirtualIntMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jint result; - va_start(args,methodID); - result = functions->CallNonvirtualIntMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jint CallNonvirtualIntMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualIntMethodV(this,obj,clazz, - methodID,args); - } - jint CallNonvirtualIntMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualIntMethodA(this,obj,clazz, - methodID,args); - } - - jlong CallNonvirtualLongMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jlong result; - va_start(args,methodID); - result = functions->CallNonvirtualLongMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jlong CallNonvirtualLongMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualLongMethodV(this,obj,clazz, - methodID,args); - } - jlong CallNonvirtualLongMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualLongMethodA(this,obj,clazz, - methodID,args); - } - - jfloat CallNonvirtualFloatMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jfloat result; - va_start(args,methodID); - result = functions->CallNonvirtualFloatMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jfloat CallNonvirtualFloatMethodV(jobject obj, jclass clazz, - jmethodID methodID, - va_list args) { - return functions->CallNonvirtualFloatMethodV(this,obj,clazz, - methodID,args); - } - jfloat CallNonvirtualFloatMethodA(jobject obj, jclass clazz, - jmethodID methodID, - const jvalue * args) { - return functions->CallNonvirtualFloatMethodA(this,obj,clazz, - methodID,args); - } - - jdouble CallNonvirtualDoubleMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jdouble result; - va_start(args,methodID); - result = functions->CallNonvirtualDoubleMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jdouble CallNonvirtualDoubleMethodV(jobject obj, jclass clazz, - jmethodID methodID, - va_list args) { - return functions->CallNonvirtualDoubleMethodV(this,obj,clazz, - methodID,args); - } - jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass clazz, - jmethodID methodID, - const jvalue * args) { - return functions->CallNonvirtualDoubleMethodA(this,obj,clazz, - methodID,args); - } - - void CallNonvirtualVoidMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - va_start(args,methodID); - functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); - va_end(args); - } - void CallNonvirtualVoidMethodV(jobject obj, jclass clazz, - jmethodID methodID, - va_list args) { - functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); - } - void CallNonvirtualVoidMethodA(jobject obj, jclass clazz, - jmethodID methodID, - const jvalue * args) { - functions->CallNonvirtualVoidMethodA(this,obj,clazz,methodID,args); - } - - jfieldID GetFieldID(jclass clazz, const char *name, - const char *sig) { - return functions->GetFieldID(this,clazz,name,sig); - } - - jobject GetObjectField(jobject obj, jfieldID fieldID) { - return functions->GetObjectField(this,obj,fieldID); - } - jboolean GetBooleanField(jobject obj, jfieldID fieldID) { - return functions->GetBooleanField(this,obj,fieldID); - } - jbyte GetByteField(jobject obj, jfieldID fieldID) { - return functions->GetByteField(this,obj,fieldID); - } - jchar GetCharField(jobject obj, jfieldID fieldID) { - return functions->GetCharField(this,obj,fieldID); - } - jshort GetShortField(jobject obj, jfieldID fieldID) { - return functions->GetShortField(this,obj,fieldID); - } - jint GetIntField(jobject obj, jfieldID fieldID) { - return functions->GetIntField(this,obj,fieldID); - } - jlong GetLongField(jobject obj, jfieldID fieldID) { - return functions->GetLongField(this,obj,fieldID); - } - jfloat GetFloatField(jobject obj, jfieldID fieldID) { - return functions->GetFloatField(this,obj,fieldID); - } - jdouble GetDoubleField(jobject obj, jfieldID fieldID) { - return functions->GetDoubleField(this,obj,fieldID); - } - - void SetObjectField(jobject obj, jfieldID fieldID, jobject val) { - functions->SetObjectField(this,obj,fieldID,val); - } - void SetBooleanField(jobject obj, jfieldID fieldID, - jboolean val) { - functions->SetBooleanField(this,obj,fieldID,val); - } - void SetByteField(jobject obj, jfieldID fieldID, - jbyte val) { - functions->SetByteField(this,obj,fieldID,val); - } - void SetCharField(jobject obj, jfieldID fieldID, - jchar val) { - functions->SetCharField(this,obj,fieldID,val); - } - void SetShortField(jobject obj, jfieldID fieldID, - jshort val) { - functions->SetShortField(this,obj,fieldID,val); - } - void SetIntField(jobject obj, jfieldID fieldID, - jint val) { - functions->SetIntField(this,obj,fieldID,val); - } - void SetLongField(jobject obj, jfieldID fieldID, - jlong val) { - functions->SetLongField(this,obj,fieldID,val); - } - void SetFloatField(jobject obj, jfieldID fieldID, - jfloat val) { - functions->SetFloatField(this,obj,fieldID,val); - } - void SetDoubleField(jobject obj, jfieldID fieldID, - jdouble val) { - functions->SetDoubleField(this,obj,fieldID,val); - } - - jmethodID GetStaticMethodID(jclass clazz, const char *name, - const char *sig) { - return functions->GetStaticMethodID(this,clazz,name,sig); - } - - jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID, - ...) { - va_list args; - jobject result; - va_start(args,methodID); - result = functions->CallStaticObjectMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID, - va_list args) { - return functions->CallStaticObjectMethodV(this,clazz,methodID,args); - } - jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID, - const jvalue *args) { - return functions->CallStaticObjectMethodA(this,clazz,methodID,args); - } - - jboolean CallStaticBooleanMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jboolean result; - va_start(args,methodID); - result = functions->CallStaticBooleanMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jboolean CallStaticBooleanMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticBooleanMethodV(this,clazz,methodID,args); - } - jboolean CallStaticBooleanMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticBooleanMethodA(this,clazz,methodID,args); - } - - jbyte CallStaticByteMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jbyte result; - va_start(args,methodID); - result = functions->CallStaticByteMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jbyte CallStaticByteMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticByteMethodV(this,clazz,methodID,args); - } - jbyte CallStaticByteMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticByteMethodA(this,clazz,methodID,args); - } - - jchar CallStaticCharMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jchar result; - va_start(args,methodID); - result = functions->CallStaticCharMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jchar CallStaticCharMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticCharMethodV(this,clazz,methodID,args); - } - jchar CallStaticCharMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticCharMethodA(this,clazz,methodID,args); - } - - jshort CallStaticShortMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jshort result; - va_start(args,methodID); - result = functions->CallStaticShortMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jshort CallStaticShortMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticShortMethodV(this,clazz,methodID,args); - } - jshort CallStaticShortMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticShortMethodA(this,clazz,methodID,args); - } - - jint CallStaticIntMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jint result; - va_start(args,methodID); - result = functions->CallStaticIntMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jint CallStaticIntMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticIntMethodV(this,clazz,methodID,args); - } - jint CallStaticIntMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticIntMethodA(this,clazz,methodID,args); - } - - jlong CallStaticLongMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jlong result; - va_start(args,methodID); - result = functions->CallStaticLongMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jlong CallStaticLongMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticLongMethodV(this,clazz,methodID,args); - } - jlong CallStaticLongMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticLongMethodA(this,clazz,methodID,args); - } - - jfloat CallStaticFloatMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jfloat result; - va_start(args,methodID); - result = functions->CallStaticFloatMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jfloat CallStaticFloatMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticFloatMethodV(this,clazz,methodID,args); - } - jfloat CallStaticFloatMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticFloatMethodA(this,clazz,methodID,args); - } - - jdouble CallStaticDoubleMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jdouble result; - va_start(args,methodID); - result = functions->CallStaticDoubleMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jdouble CallStaticDoubleMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticDoubleMethodV(this,clazz,methodID,args); - } - jdouble CallStaticDoubleMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticDoubleMethodA(this,clazz,methodID,args); - } - - void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...) { - va_list args; - va_start(args,methodID); - functions->CallStaticVoidMethodV(this,cls,methodID,args); - va_end(args); - } - void CallStaticVoidMethodV(jclass cls, jmethodID methodID, - va_list args) { - functions->CallStaticVoidMethodV(this,cls,methodID,args); - } - void CallStaticVoidMethodA(jclass cls, jmethodID methodID, - const jvalue * args) { - functions->CallStaticVoidMethodA(this,cls,methodID,args); - } - - jfieldID GetStaticFieldID(jclass clazz, const char *name, - const char *sig) { - return functions->GetStaticFieldID(this,clazz,name,sig); - } - jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticObjectField(this,clazz,fieldID); - } - jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticBooleanField(this,clazz,fieldID); - } - jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticByteField(this,clazz,fieldID); - } - jchar GetStaticCharField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticCharField(this,clazz,fieldID); - } - jshort GetStaticShortField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticShortField(this,clazz,fieldID); - } - jint GetStaticIntField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticIntField(this,clazz,fieldID); - } - jlong GetStaticLongField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticLongField(this,clazz,fieldID); - } - jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticFloatField(this,clazz,fieldID); - } - jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticDoubleField(this,clazz,fieldID); - } - - void SetStaticObjectField(jclass clazz, jfieldID fieldID, - jobject value) { - functions->SetStaticObjectField(this,clazz,fieldID,value); - } - void SetStaticBooleanField(jclass clazz, jfieldID fieldID, - jboolean value) { - functions->SetStaticBooleanField(this,clazz,fieldID,value); - } - void SetStaticByteField(jclass clazz, jfieldID fieldID, - jbyte value) { - functions->SetStaticByteField(this,clazz,fieldID,value); - } - void SetStaticCharField(jclass clazz, jfieldID fieldID, - jchar value) { - functions->SetStaticCharField(this,clazz,fieldID,value); - } - void SetStaticShortField(jclass clazz, jfieldID fieldID, - jshort value) { - functions->SetStaticShortField(this,clazz,fieldID,value); - } - void SetStaticIntField(jclass clazz, jfieldID fieldID, - jint value) { - functions->SetStaticIntField(this,clazz,fieldID,value); - } - void SetStaticLongField(jclass clazz, jfieldID fieldID, - jlong value) { - functions->SetStaticLongField(this,clazz,fieldID,value); - } - void SetStaticFloatField(jclass clazz, jfieldID fieldID, - jfloat value) { - functions->SetStaticFloatField(this,clazz,fieldID,value); - } - void SetStaticDoubleField(jclass clazz, jfieldID fieldID, - jdouble value) { - functions->SetStaticDoubleField(this,clazz,fieldID,value); - } - - jstring NewString(const jchar *unicode, jsize len) { - return functions->NewString(this,unicode,len); - } - jsize GetStringLength(jstring str) { - return functions->GetStringLength(this,str); - } - const jchar *GetStringChars(jstring str, jboolean *isCopy) { - return functions->GetStringChars(this,str,isCopy); - } - void ReleaseStringChars(jstring str, const jchar *chars) { - functions->ReleaseStringChars(this,str,chars); - } - - jstring NewStringUTF(const char *utf) { - return functions->NewStringUTF(this,utf); - } - jsize GetStringUTFLength(jstring str) { - return functions->GetStringUTFLength(this,str); - } - const char* GetStringUTFChars(jstring str, jboolean *isCopy) { - return functions->GetStringUTFChars(this,str,isCopy); - } - void ReleaseStringUTFChars(jstring str, const char* chars) { - functions->ReleaseStringUTFChars(this,str,chars); - } - - jsize GetArrayLength(jarray array) { - return functions->GetArrayLength(this,array); - } - - jobjectArray NewObjectArray(jsize len, jclass clazz, - jobject init) { - return functions->NewObjectArray(this,len,clazz,init); - } - jobject GetObjectArrayElement(jobjectArray array, jsize index) { - return functions->GetObjectArrayElement(this,array,index); - } - void SetObjectArrayElement(jobjectArray array, jsize index, - jobject val) { - functions->SetObjectArrayElement(this,array,index,val); - } - - jbooleanArray NewBooleanArray(jsize len) { - return functions->NewBooleanArray(this,len); - } - jbyteArray NewByteArray(jsize len) { - return functions->NewByteArray(this,len); - } - jcharArray NewCharArray(jsize len) { - return functions->NewCharArray(this,len); - } - jshortArray NewShortArray(jsize len) { - return functions->NewShortArray(this,len); - } - jintArray NewIntArray(jsize len) { - return functions->NewIntArray(this,len); - } - jlongArray NewLongArray(jsize len) { - return functions->NewLongArray(this,len); - } - jfloatArray NewFloatArray(jsize len) { - return functions->NewFloatArray(this,len); - } - jdoubleArray NewDoubleArray(jsize len) { - return functions->NewDoubleArray(this,len); - } - - jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) { - return functions->GetBooleanArrayElements(this,array,isCopy); - } - jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy) { - return functions->GetByteArrayElements(this,array,isCopy); - } - jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) { - return functions->GetCharArrayElements(this,array,isCopy); - } - jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy) { - return functions->GetShortArrayElements(this,array,isCopy); - } - jint * GetIntArrayElements(jintArray array, jboolean *isCopy) { - return functions->GetIntArrayElements(this,array,isCopy); - } - jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy) { - return functions->GetLongArrayElements(this,array,isCopy); - } - jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy) { - return functions->GetFloatArrayElements(this,array,isCopy); - } - jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) { - return functions->GetDoubleArrayElements(this,array,isCopy); - } - - void ReleaseBooleanArrayElements(jbooleanArray array, - jboolean *elems, - jint mode) { - functions->ReleaseBooleanArrayElements(this,array,elems,mode); - } - void ReleaseByteArrayElements(jbyteArray array, - jbyte *elems, - jint mode) { - functions->ReleaseByteArrayElements(this,array,elems,mode); - } - void ReleaseCharArrayElements(jcharArray array, - jchar *elems, - jint mode) { - functions->ReleaseCharArrayElements(this,array,elems,mode); - } - void ReleaseShortArrayElements(jshortArray array, - jshort *elems, - jint mode) { - functions->ReleaseShortArrayElements(this,array,elems,mode); - } - void ReleaseIntArrayElements(jintArray array, - jint *elems, - jint mode) { - functions->ReleaseIntArrayElements(this,array,elems,mode); - } - void ReleaseLongArrayElements(jlongArray array, - jlong *elems, - jint mode) { - functions->ReleaseLongArrayElements(this,array,elems,mode); - } - void ReleaseFloatArrayElements(jfloatArray array, - jfloat *elems, - jint mode) { - functions->ReleaseFloatArrayElements(this,array,elems,mode); - } - void ReleaseDoubleArrayElements(jdoubleArray array, - jdouble *elems, - jint mode) { - functions->ReleaseDoubleArrayElements(this,array,elems,mode); - } - - void GetBooleanArrayRegion(jbooleanArray array, - jsize start, jsize len, jboolean *buf) { - functions->GetBooleanArrayRegion(this,array,start,len,buf); - } - void GetByteArrayRegion(jbyteArray array, - jsize start, jsize len, jbyte *buf) { - functions->GetByteArrayRegion(this,array,start,len,buf); - } - void GetCharArrayRegion(jcharArray array, - jsize start, jsize len, jchar *buf) { - functions->GetCharArrayRegion(this,array,start,len,buf); - } - void GetShortArrayRegion(jshortArray array, - jsize start, jsize len, jshort *buf) { - functions->GetShortArrayRegion(this,array,start,len,buf); - } - void GetIntArrayRegion(jintArray array, - jsize start, jsize len, jint *buf) { - functions->GetIntArrayRegion(this,array,start,len,buf); - } - void GetLongArrayRegion(jlongArray array, - jsize start, jsize len, jlong *buf) { - functions->GetLongArrayRegion(this,array,start,len,buf); - } - void GetFloatArrayRegion(jfloatArray array, - jsize start, jsize len, jfloat *buf) { - functions->GetFloatArrayRegion(this,array,start,len,buf); - } - void GetDoubleArrayRegion(jdoubleArray array, - jsize start, jsize len, jdouble *buf) { - functions->GetDoubleArrayRegion(this,array,start,len,buf); - } - - void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, - const jboolean *buf) { - functions->SetBooleanArrayRegion(this,array,start,len,buf); - } - void SetByteArrayRegion(jbyteArray array, jsize start, jsize len, - const jbyte *buf) { - functions->SetByteArrayRegion(this,array,start,len,buf); - } - void SetCharArrayRegion(jcharArray array, jsize start, jsize len, - const jchar *buf) { - functions->SetCharArrayRegion(this,array,start,len,buf); - } - void SetShortArrayRegion(jshortArray array, jsize start, jsize len, - const jshort *buf) { - functions->SetShortArrayRegion(this,array,start,len,buf); - } - void SetIntArrayRegion(jintArray array, jsize start, jsize len, - const jint *buf) { - functions->SetIntArrayRegion(this,array,start,len,buf); - } - void SetLongArrayRegion(jlongArray array, jsize start, jsize len, - const jlong *buf) { - functions->SetLongArrayRegion(this,array,start,len,buf); - } - void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, - const jfloat *buf) { - functions->SetFloatArrayRegion(this,array,start,len,buf); - } - void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, - const jdouble *buf) { - functions->SetDoubleArrayRegion(this,array,start,len,buf); - } - - jint RegisterNatives(jclass clazz, const JNINativeMethod *methods, - jint nMethods) { - return functions->RegisterNatives(this,clazz,methods,nMethods); - } - jint UnregisterNatives(jclass clazz) { - return functions->UnregisterNatives(this,clazz); - } - - jint MonitorEnter(jobject obj) { - return functions->MonitorEnter(this,obj); - } - jint MonitorExit(jobject obj) { - return functions->MonitorExit(this,obj); - } - - jint GetJavaVM(JavaVM **vm) { - return functions->GetJavaVM(this,vm); - } - - void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) { - functions->GetStringRegion(this,str,start,len,buf); - } - void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) { - functions->GetStringUTFRegion(this,str,start,len,buf); - } - - void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) { - return functions->GetPrimitiveArrayCritical(this,array,isCopy); - } - void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) { - functions->ReleasePrimitiveArrayCritical(this,array,carray,mode); - } - - const jchar * GetStringCritical(jstring string, jboolean *isCopy) { - return functions->GetStringCritical(this,string,isCopy); - } - void ReleaseStringCritical(jstring string, const jchar *cstring) { - functions->ReleaseStringCritical(this,string,cstring); - } - - jweak NewWeakGlobalRef(jobject obj) { - return functions->NewWeakGlobalRef(this,obj); - } - void DeleteWeakGlobalRef(jweak ref) { - functions->DeleteWeakGlobalRef(this,ref); - } - - jboolean ExceptionCheck() { - return functions->ExceptionCheck(this); - } - - jobject NewDirectByteBuffer(void* address, jlong capacity) { - return functions->NewDirectByteBuffer(this, address, capacity); - } - void* GetDirectBufferAddress(jobject buf) { - return functions->GetDirectBufferAddress(this, buf); - } - jlong GetDirectBufferCapacity(jobject buf) { - return functions->GetDirectBufferCapacity(this, buf); - } - jobjectRefType GetObjectRefType(jobject obj) { - return functions->GetObjectRefType(this, obj); - } - - /* Module Features */ - - jobject GetModule(jclass clazz) { - return functions->GetModule(this, clazz); - } - -#endif /* __cplusplus */ -}; - -typedef struct JavaVMOption { - char *optionString; - void *extraInfo; -} JavaVMOption; - -typedef struct JavaVMInitArgs { - jint version; - - jint nOptions; - JavaVMOption *options; - jboolean ignoreUnrecognized; -} JavaVMInitArgs; - -typedef struct JavaVMAttachArgs { - jint version; - - char *name; - jobject group; -} JavaVMAttachArgs; - -/* These will be VM-specific. */ - -#define JDK1_2 -#define JDK1_4 - -/* End VM-specific. */ - -struct JNIInvokeInterface_ { - void *reserved0; - void *reserved1; - void *reserved2; - - jint (JNICALL *DestroyJavaVM)(JavaVM *vm); - - jint (JNICALL *AttachCurrentThread)(JavaVM *vm, void **penv, void *args); - - jint (JNICALL *DetachCurrentThread)(JavaVM *vm); - - jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version); - - jint (JNICALL *AttachCurrentThreadAsDaemon)(JavaVM *vm, void **penv, void *args); -}; - -struct JavaVM_ { - const struct JNIInvokeInterface_ *functions; -#ifdef __cplusplus - - jint DestroyJavaVM() { - return functions->DestroyJavaVM(this); - } - jint AttachCurrentThread(void **penv, void *args) { - return functions->AttachCurrentThread(this, penv, args); - } - jint DetachCurrentThread() { - return functions->DetachCurrentThread(this); - } - - jint GetEnv(void **penv, jint version) { - return functions->GetEnv(this, penv, version); - } - jint AttachCurrentThreadAsDaemon(void **penv, void *args) { - return functions->AttachCurrentThreadAsDaemon(this, penv, args); - } -#endif -}; - -#ifdef _JNI_IMPLEMENTATION_ -#define _JNI_IMPORT_OR_EXPORT_ JNIEXPORT -#else -#define _JNI_IMPORT_OR_EXPORT_ JNIIMPORT -#endif -_JNI_IMPORT_OR_EXPORT_ jint JNICALL -JNI_GetDefaultJavaVMInitArgs(void *args); - -_JNI_IMPORT_OR_EXPORT_ jint JNICALL -JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args); - -_JNI_IMPORT_OR_EXPORT_ jint JNICALL -JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *); - -/* Defined by native libraries. */ -JNIEXPORT jint JNICALL -JNI_OnLoad(JavaVM *vm, void *reserved); - -JNIEXPORT void JNICALL -JNI_OnUnload(JavaVM *vm, void *reserved); - -#define JNI_VERSION_1_1 0x00010001 -#define JNI_VERSION_1_2 0x00010002 -#define JNI_VERSION_1_4 0x00010004 -#define JNI_VERSION_1_6 0x00010006 -#define JNI_VERSION_1_8 0x00010008 -#define JNI_VERSION_9 0x00090000 - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ - -#endif /* !_JAVASOFT_JNI_H_ */ diff --git a/src/hotspot/share/prims/jniCheck.cpp b/src/hotspot/share/prims/jniCheck.cpp index 6ec762a14d8..6d8d27ccccd 100644 --- a/src/hotspot/share/prims/jniCheck.cpp +++ b/src/hotspot/share/prims/jniCheck.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "jni.h" #include "classfile/javaClasses.inline.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" @@ -30,7 +31,6 @@ #include "oops/instanceKlass.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" -#include "prims/jni.h" #include "prims/jniCheck.hpp" #include "prims/jvm.h" #include "prims/jvm_misc.hpp" diff --git a/src/hotspot/share/prims/jniExport.hpp b/src/hotspot/share/prims/jniExport.hpp index 9c93de8c72d..a2dfda8c968 100644 --- a/src/hotspot/share/prims/jniExport.hpp +++ b/src/hotspot/share/prims/jniExport.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_VM_PRIMS_JNI_EXPORT_HPP #define SHARE_VM_PRIMS_JNI_EXPORT_HPP -#include "prims/jni.h" +#include "jni.h" #include "prims/jvmtiExport.hpp" class JniExportedInterface { diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 5aff18f478b..faca8621afa 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -669,7 +669,6 @@ JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle)) // Store check (mark entire object and let gc sort it out) BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->has_write_region_opt(), "Barrier set does not have write_region"); bs->write_region(MemRegion((HeapWord*)new_obj_oop, size)); Handle new_obj(THREAD, new_obj_oop); @@ -3356,24 +3355,6 @@ JVM_END // ObjectInputStream /////////////////////////////////////////////////////////////// -bool force_verify_field_access(Klass* current_class, Klass* field_class, AccessFlags access, bool classloader_only) { - if (current_class == NULL) { - return true; - } - if ((current_class == field_class) || access.is_public()) { - return true; - } - - if (access.is_protected()) { - // See if current_class is a subclass of field_class - if (current_class->is_subclass_of(field_class)) { - return true; - } - } - - return (!access.is_private() && InstanceKlass::cast(current_class)->is_same_class_package(field_class)); -} - // Return the first user-defined class loader up the execution stack, or null // if only code from the bootstrap or platform class loader is on the stack. diff --git a/src/hotspot/share/prims/jvm.h b/src/hotspot/share/prims/jvm.h index b25724a1c7d..1103c7628f5 100644 --- a/src/hotspot/share/prims/jvm.h +++ b/src/hotspot/share/prims/jvm.h @@ -25,7 +25,7 @@ #ifndef SHARE_VM_PRIMS_JVM_H #define SHARE_VM_PRIMS_JVM_H -#include "prims/jni.h" +#include "jni.h" #include "utilities/macros.hpp" #include OS_HEADER_H(jvm) diff --git a/src/hotspot/share/prims/jvm_misc.hpp b/src/hotspot/share/prims/jvm_misc.hpp index 39b2d7199d4..98b5e5c692f 100644 --- a/src/hotspot/share/prims/jvm_misc.hpp +++ b/src/hotspot/share/prims/jvm_misc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_VM_PRIMS_JVM_MISC_HPP #define SHARE_VM_PRIMS_JVM_MISC_HPP -#include "prims/jni.h" +#include "jni.h" #include "runtime/handles.hpp" // Useful entry points shared by JNI and JVM interface. diff --git a/src/hotspot/share/prims/jvmtiExport.hpp b/src/hotspot/share/prims/jvmtiExport.hpp index 6c4fc7f286e..7bae70b626e 100644 --- a/src/hotspot/share/prims/jvmtiExport.hpp +++ b/src/hotspot/share/prims/jvmtiExport.hpp @@ -37,7 +37,7 @@ #include "utilities/macros.hpp" // Must be included after jvmti.h. -#include "code/jvmticmlr.h" +#include "jvmticmlr.h" // Forward declarations diff --git a/src/hotspot/share/prims/jvmtiRawMonitor.cpp b/src/hotspot/share/prims/jvmtiRawMonitor.cpp index 3ce6cf760b4..23fc9e08d71 100644 --- a/src/hotspot/share/prims/jvmtiRawMonitor.cpp +++ b/src/hotspot/share/prims/jvmtiRawMonitor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -127,7 +127,7 @@ JvmtiRawMonitor::is_valid() { int JvmtiRawMonitor::SimpleEnter (Thread * Self) { for (;;) { - if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) { + if (Atomic::cmpxchg(Self, &_owner, (void*)NULL) == NULL) { return OS_OK ; } @@ -139,7 +139,7 @@ int JvmtiRawMonitor::SimpleEnter (Thread * Self) { Node._next = _EntryList ; _EntryList = &Node ; OrderAccess::fence() ; - if (_owner == NULL && Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) { + if (_owner == NULL && Atomic::cmpxchg(Self, &_owner, (void*)NULL) == NULL) { _EntryList = Node._next ; RawMonitor_lock->unlock() ; return OS_OK ; @@ -153,7 +153,7 @@ int JvmtiRawMonitor::SimpleEnter (Thread * Self) { int JvmtiRawMonitor::SimpleExit (Thread * Self) { guarantee (_owner == Self, "invariant") ; - OrderAccess::release_store_ptr (&_owner, NULL) ; + OrderAccess::release_store(&_owner, (void*)NULL) ; OrderAccess::fence() ; if (_EntryList == NULL) return OS_OK ; ObjectWaiter * w ; @@ -277,10 +277,10 @@ int JvmtiRawMonitor::raw_enter(TRAPS) { jt->SR_lock()->lock_without_safepoint_check(); } // guarded by SR_lock to avoid racing with new external suspend requests. - Contended = Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) ; + Contended = Atomic::cmpxchg(THREAD, &_owner, (void*)NULL); jt->SR_lock()->unlock(); } else { - Contended = Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) ; + Contended = Atomic::cmpxchg(THREAD, &_owner, (void*)NULL); } if (Contended == THREAD) { diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index 336ac07b644..c73842e0500 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -158,6 +158,11 @@ bool VM_RedefineClasses::doit_prologue() { ClassLoaderData* cld = _scratch_classes[i]->class_loader_data(); // Free the memory for this class at class unloading time. Not before // because CMS might think this is still live. + InstanceKlass* ik = get_ik(_class_defs[i].klass); + if (ik->get_cached_class_file() == _scratch_classes[i]->get_cached_class_file()) { + // Don't double-free cached_class_file copied from the original class if error. + _scratch_classes[i]->set_cached_class_file(NULL); + } cld->add_to_deallocate_list(InstanceKlass::cast(_scratch_classes[i])); } } @@ -3946,12 +3951,12 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass, // with them was cached on the scratch class, move to the_class. // Note: we still want to do this if nothing needed caching since it // should get cleared in the_class too. - if (the_class->get_cached_class_file_bytes() == 0) { + if (the_class->get_cached_class_file() == 0) { // the_class doesn't have a cache yet so copy it the_class->set_cached_class_file(scratch_class->get_cached_class_file()); } - else if (scratch_class->get_cached_class_file_bytes() != - the_class->get_cached_class_file_bytes()) { + else if (scratch_class->get_cached_class_file() != + the_class->get_cached_class_file()) { // The same class can be present twice in the scratch classes list or there // are multiple concurrent RetransformClasses calls on different threads. // In such cases we have to deallocate scratch_class cached_class_file. diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index 7aaa1341dd6..25807a2a626 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -3026,8 +3026,7 @@ inline bool VM_HeapWalkOperation::collect_simple_roots() { // Preloaded classes and loader from the system dictionary blk.set_kind(JVMTI_HEAP_REFERENCE_SYSTEM_CLASS); SystemDictionary::always_strong_oops_do(&blk); - KlassToOopClosure klass_blk(&blk); - ClassLoaderDataGraph::always_strong_oops_do(&blk, &klass_blk, false); + ClassLoaderDataGraph::always_strong_oops_do(&blk, false); if (blk.stopped()) { return false; } diff --git a/src/hotspot/share/prims/jvmtiThreadState.hpp b/src/hotspot/share/prims/jvmtiThreadState.hpp index 3a7ddb66fc3..9dfb9b85309 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.hpp +++ b/src/hotspot/share/prims/jvmtiThreadState.hpp @@ -411,21 +411,21 @@ class RedefineVerifyMark : public StackObj { private: JvmtiThreadState* _state; Klass* _scratch_class; - Handle _scratch_mirror; + OopHandle _scratch_mirror; public: RedefineVerifyMark(Klass* the_class, Klass* scratch_class, JvmtiThreadState *state) : _state(state), _scratch_class(scratch_class) { _state->set_class_versions_map(the_class, scratch_class); - _scratch_mirror = Handle(Thread::current(), _scratch_class->java_mirror()); - _scratch_class->set_java_mirror(the_class->java_mirror()); + _scratch_mirror = _scratch_class->java_mirror_handle(); + _scratch_class->set_java_mirror_handle(the_class->java_mirror_handle()); } ~RedefineVerifyMark() { // Restore the scratch class's mirror, so when scratch_class is removed // the correct mirror pointing to it can be cleared. - _scratch_class->set_java_mirror(_scratch_mirror()); + _scratch_class->set_java_mirror_handle(_scratch_mirror); _state->clear_class_versions_map(); } }; diff --git a/src/hotspot/share/prims/perf.cpp b/src/hotspot/share/prims/perf.cpp index 1cbb9568298..afb26639e52 100644 --- a/src/hotspot/share/prims/perf.cpp +++ b/src/hotspot/share/prims/perf.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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,11 +23,11 @@ */ #include "precompiled.hpp" +#include "jni.h" #include "classfile/vmSymbols.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" -#include "prims/jni.h" #include "prims/jvm.h" #include "runtime/interfaceSupport.hpp" #include "runtime/perfData.hpp" diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index d9b29081fb9..63436feaa74 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "jni.h" #include "classfile/classFileStream.hpp" #include "classfile/vmSymbols.hpp" #include "memory/allocation.inline.hpp" @@ -30,7 +31,6 @@ #include "oops/fieldStreams.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" -#include "prims/jni.h" #include "prims/jvm.h" #include "prims/unsafe.hpp" #include "runtime/atomic.hpp" diff --git a/src/hotspot/share/prims/wbtestmethods/parserTests.cpp b/src/hotspot/share/prims/wbtestmethods/parserTests.cpp index 3ed2ab83ae0..aa01151d785 100644 --- a/src/hotspot/share/prims/wbtestmethods/parserTests.cpp +++ b/src/hotspot/share/prims/wbtestmethods/parserTests.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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,12 +23,12 @@ */ #include "precompiled.hpp" +#include "jni.h" #include "classfile/javaClasses.inline.hpp" #include "classfile/symbolTable.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/objArrayOop.inline.hpp" -#include "prims/jni.h" #include "prims/whitebox.hpp" #include "prims/wbtestmethods/parserTests.hpp" #include "runtime/interfaceSupport.hpp" diff --git a/src/hotspot/share/prims/wbtestmethods/parserTests.hpp b/src/hotspot/share/prims/wbtestmethods/parserTests.hpp index e791225a43f..cdde04fbf94 100644 --- a/src/hotspot/share/prims/wbtestmethods/parserTests.hpp +++ b/src/hotspot/share/prims/wbtestmethods/parserTests.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -24,7 +24,7 @@ #ifndef SHARE_VM_PRIMS_WBTESTMETHODS_PARSERTESTS_H #define SHARE_VM_PRIMS_WBTESTMETHODS_PARSERTESTS_H -#include "prims/jni.h" +#include "jni.h" #include "prims/whitebox.hpp" WB_METHOD_DECLARE(jobjectArray) WB_ParseCommandLine(JNIEnv* env, jobject o, jstring args, jchar delim, jobjectArray arguments); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 7d1567185e4..f7cb20b9ab8 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -448,7 +448,7 @@ WB_END WB_ENTRY(jboolean, WB_G1InConcurrentMark(JNIEnv* env, jobject o)) if (UseG1GC) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - return g1h->concurrent_mark()->cmThread()->during_cycle(); + return g1h->concurrent_mark()->cm_thread()->during_cycle(); } THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_G1InConcurrentMark: G1 GC is not enabled"); WB_END @@ -456,7 +456,7 @@ WB_END WB_ENTRY(jboolean, WB_G1StartMarkCycle(JNIEnv* env, jobject o)) if (UseG1GC) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - if (!g1h->concurrent_mark()->cmThread()->during_cycle()) { + if (!g1h->concurrent_mark()->cm_thread()->during_cycle()) { g1h->collect(GCCause::_wb_conc_mark); return true; } diff --git a/src/hotspot/share/prims/whitebox.hpp b/src/hotspot/share/prims/whitebox.hpp index 8402195fcaf..10432fc6fcf 100644 --- a/src/hotspot/share/prims/whitebox.hpp +++ b/src/hotspot/share/prims/whitebox.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_VM_PRIMS_WHITEBOX_HPP #define SHARE_VM_PRIMS_WHITEBOX_HPP -#include "prims/jni.h" +#include "jni.h" #include "utilities/exceptions.hpp" #include "memory/allocation.hpp" diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 0213dbc3b1c..a7ca6ce09bd 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -377,6 +377,7 @@ static SpecialFlag const special_jvm_flags[] = { // --- Non-alias flags - sorted by obsolete_in then expired_in: { "MaxGCMinorPauseMillis", JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() }, { "UseConcMarkSweepGC", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() }, + { "AssumeMP", JDK_Version::jdk(10),JDK_Version::undefined(), JDK_Version::undefined() }, { "MonitorInUseLists", JDK_Version::jdk(10),JDK_Version::undefined(), JDK_Version::undefined() }, { "MaxRAMFraction", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() }, { "MinRAMFraction", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() }, @@ -4476,16 +4477,6 @@ jint Arguments::apply_ergo() { set_shared_spaces_flags(); -#if defined(SPARC) - // BIS instructions require 'membar' instruction regardless of the number - // of CPUs because in virtualized/container environments which might use only 1 - // CPU, BIS instructions may produce incorrect results. - - if (FLAG_IS_DEFAULT(AssumeMP)) { - FLAG_SET_DEFAULT(AssumeMP, true); - } -#endif - // Check the GC selections again. if (!check_gc_consistency()) { return JNI_EINVAL; diff --git a/src/hotspot/share/runtime/atomic.hpp b/src/hotspot/share/runtime/atomic.hpp index 108c841ed96..9f3411c68c1 100644 --- a/src/hotspot/share/runtime/atomic.hpp +++ b/src/hotspot/share/runtime/atomic.hpp @@ -44,7 +44,7 @@ enum cmpxchg_memory_order { }; class Atomic : AllStatic { - public: +public: // Atomic operations on jlong types are not available on all 32-bit // platforms. If atomic ops on jlongs are defined here they must only // be used from code that verifies they are available at runtime and @@ -64,24 +64,17 @@ class Atomic : AllStatic { // we can prove that a weaker form is sufficiently safe. // Atomically store to a location - inline static void store (jbyte store_value, jbyte* dest); - inline static void store (jshort store_value, jshort* dest); - inline static void store (jint store_value, jint* dest); - // See comment above about using jlong atomics on 32-bit platforms - inline static void store (jlong store_value, jlong* dest); - inline static void store_ptr(intptr_t store_value, intptr_t* dest); - inline static void store_ptr(void* store_value, void* dest); + // The type T must be either a pointer type convertible to or equal + // to D, an integral/enum type equal to D, or a type equal to D that + // is primitive convertible using PrimitiveConversions. + template + inline static void store(T store_value, volatile D* dest); - inline static void store (jbyte store_value, volatile jbyte* dest); - inline static void store (jshort store_value, volatile jshort* dest); - inline static void store (jint store_value, volatile jint* dest); - // See comment above about using jlong atomics on 32-bit platforms - inline static void store (jlong store_value, volatile jlong* dest); - inline static void store_ptr(intptr_t store_value, volatile intptr_t* dest); - inline static void store_ptr(void* store_value, volatile void* dest); - - // See comment above about using jlong atomics on 32-bit platforms - inline static jlong load(const volatile jlong* src); + // Atomically load from a location + // The type T must be either a pointer type, an integral/enum type, + // or a type that is primitive convertible using PrimitiveConversions. + template + inline static T load(const volatile T* dest); // Atomically add to a location. Returns updated value. add*() provide: // add-value-to-dest @@ -89,37 +82,33 @@ class Atomic : AllStatic { template inline static D add(I add_value, D volatile* dest); - inline static intptr_t add_ptr(intptr_t add_value, volatile intptr_t* dest) { - return add(add_value, dest); - } + template + inline static D sub(I sub_value, D volatile* dest); - inline static void* add_ptr(intptr_t add_value, volatile void* dest) { - return add(add_value, reinterpret_cast(dest)); - } - - // Atomically increment location. inc*() provide: + // Atomically increment location. inc() provide: // increment-dest - inline static void inc (volatile jint* dest); - inline static void inc (volatile jshort* dest); - inline static void inc (volatile size_t* dest); - inline static void inc_ptr(volatile intptr_t* dest); - inline static void inc_ptr(volatile void* dest); + // The type D may be either a pointer type, or an integral + // type. If it is a pointer type, then the increment is + // scaled to the size of the type pointed to by the pointer. + template + inline static void inc(D volatile* dest); - // Atomically decrement a location. dec*() provide: + // Atomically decrement a location. dec() provide: // decrement-dest - inline static void dec (volatile jint* dest); - inline static void dec (volatile jshort* dest); - inline static void dec (volatile size_t* dest); - inline static void dec_ptr(volatile intptr_t* dest); - inline static void dec_ptr(volatile void* dest); + // The type D may be either a pointer type, or an integral + // type. If it is a pointer type, then the decrement is + // scaled to the size of the type pointed to by the pointer. + template + inline static void dec(D volatile* dest); // Performs atomic exchange of *dest with exchange_value. Returns old // prior value of *dest. xchg*() provide: // exchange-value-with-dest - inline static jint xchg (jint exchange_value, volatile jint* dest); - inline static unsigned int xchg (unsigned int exchange_value, volatile unsigned int* dest); - inline static intptr_t xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest); - inline static void* xchg_ptr(void* exchange_value, volatile void* dest); + // The type T must be either a pointer type convertible to or equal + // to D, an integral/enum type equal to D, or a type equal to D that + // is primitive convertible using PrimitiveConversions. + template + inline static D xchg(T exchange_value, volatile D* dest); // Performs atomic compare of *dest and compare_value, and exchanges // *dest with exchange_value if the comparison succeeded. Returns prior @@ -141,23 +130,6 @@ class Atomic : AllStatic { inline static bool replace_if_null(T* value, D* volatile* dest, cmpxchg_memory_order order = memory_order_conservative); - inline static intptr_t cmpxchg_ptr(intptr_t exchange_value, - volatile intptr_t* dest, - intptr_t compare_value, - cmpxchg_memory_order order = memory_order_conservative) { - return cmpxchg(exchange_value, dest, compare_value, order); - } - - inline static void* cmpxchg_ptr(void* exchange_value, - volatile void* dest, - void* compare_value, - cmpxchg_memory_order order = memory_order_conservative) { - return cmpxchg(exchange_value, - reinterpret_cast(dest), - compare_value, - order); - } - private: // Test whether From is implicitly convertible to To. // From and To must be pointer types. @@ -165,6 +137,59 @@ private: // that is needed here. template struct IsPointerConvertible; +protected: + // Dispatch handler for store. Provides type-based validity + // checking and limited conversions around calls to the platform- + // specific implementation layer provided by PlatformOp. + template + struct StoreImpl; + + // Platform-specific implementation of store. Support for sizes + // of 1, 2, 4, and (if different) pointer size bytes are required. + // The class is a function object that must be default constructable, + // with these requirements: + // + // either: + // - dest is of type D*, an integral, enum or pointer type. + // - new_value are of type T, an integral, enum or pointer type D or + // pointer type convertible to D. + // or: + // - T and D are the same and are primitive convertible using PrimitiveConversions + // and either way: + // - platform_store is an object of type PlatformStore. + // + // Then + // platform_store(new_value, dest) + // must be a valid expression. + // + // The default implementation is a volatile store. If a platform + // requires more for e.g. 64 bit stores, a specialization is required + template struct PlatformStore; + + // Dispatch handler for load. Provides type-based validity + // checking and limited conversions around calls to the platform- + // specific implementation layer provided by PlatformOp. + template + struct LoadImpl; + + // Platform-specific implementation of load. Support for sizes of + // 1, 2, 4 bytes and (if different) pointer size bytes are required. + // The class is a function object that must be default + // constructable, with these requirements: + // + // - dest is of type T*, an integral, enum or pointer type, or + // T is convertible to a primitive type using PrimitiveConversions + // - platform_load is an object of type PlatformLoad. + // + // Then + // platform_load(src) + // must be a valid expression, returning a result convertible to T. + // + // The default implementation is a volatile load. If a platform + // requires more for e.g. 64 bit loads, a specialization is required + template struct PlatformLoad; + +private: // Dispatch handler for add. Provides type-based validity checking // and limited conversions around calls to the platform-specific // implementation layer provided by PlatformAdd. @@ -280,6 +305,45 @@ private: public: // Temporary, can't be private: C++03 11.4/2. Fixed by C++11. struct CmpxchgByteUsingInt; private: + + // Dispatch handler for xchg. Provides type-based validity + // checking and limited conversions around calls to the + // platform-specific implementation layer provided by + // PlatformXchg. + template + struct XchgImpl; + + // Platform-specific implementation of xchg. Support for sizes + // of 4, and sizeof(intptr_t) are required. The class is a function + // object that must be default constructable, with these requirements: + // + // - dest is of type T*. + // - exchange_value is of type T. + // - platform_xchg is an object of type PlatformXchg. + // + // Then + // platform_xchg(exchange_value, dest) + // must be a valid expression, returning a result convertible to T. + // + // A default definition is provided, which declares a function template + // T operator()(T, T volatile*, T, cmpxchg_memory_order) const + // + // For each required size, a platform must either provide an + // appropriate definition of that function, or must entirely + // specialize the class template for that size. + template struct PlatformXchg; + + // Support for platforms that implement some variants of xchg + // using a (typically out of line) non-template helper function. + // The generic arguments passed to PlatformXchg need to be + // translated to the appropriate type for the helper function, the + // helper invoked on the translated arguments, and the result + // translated back. Type is the parameter / return type of the + // helper function. + template + static T xchg_using_helper(Fn fn, + T exchange_value, + T volatile* dest); }; template @@ -296,6 +360,131 @@ struct Atomic::IsPointerConvertible : AllStatic { static const bool value = (sizeof(yes) == sizeof(test(test_value))); }; +// Handle load for pointer, integral and enum types. +template +struct Atomic::LoadImpl< + T, + PlatformOp, + typename EnableIf::value || IsRegisteredEnum::value || IsPointer::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(T const volatile* dest) const { + // Forward to the platform handler for the size of T. + return PlatformOp()(dest); + } +}; + +// Handle load for types that have a translator. +// +// All the involved types must be identical. +// +// This translates the original call into a call on the decayed +// arguments, and returns the recovered result of that translated +// call. +template +struct Atomic::LoadImpl< + T, + PlatformOp, + typename EnableIf::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(T const volatile* dest) const { + typedef PrimitiveConversions::Translate Translator; + typedef typename Translator::Decayed Decayed; + STATIC_ASSERT(sizeof(T) == sizeof(Decayed)); + Decayed result = PlatformOp()(reinterpret_cast(dest)); + return Translator::recover(result); + } +}; + +// Default implementation of atomic load if a specific platform +// does not provide a specialization for a certain size class. +// For increased safety, the default implementation only allows +// load types that are pointer sized or smaller. If a platform still +// supports wide atomics, then it has to use specialization +// of Atomic::PlatformLoad for that wider size class. +template +struct Atomic::PlatformLoad VALUE_OBJ_CLASS_SPEC { + template + T operator()(T const volatile* dest) const { + STATIC_ASSERT(sizeof(T) <= sizeof(void*)); // wide atomics need specialization + return *dest; + } +}; + +// Handle store for integral and enum types. +// +// All the involved types must be identical. +template +struct Atomic::StoreImpl< + T, T, + PlatformOp, + typename EnableIf::value || IsRegisteredEnum::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + void operator()(T new_value, T volatile* dest) const { + // Forward to the platform handler for the size of T. + PlatformOp()(new_value, dest); + } +}; + +// Handle store for pointer types. +// +// The new_value must be implicitly convertible to the +// destination's type; it must be type-correct to store the +// new_value in the destination. +template +struct Atomic::StoreImpl< + T*, D*, + PlatformOp, + typename EnableIf::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + void operator()(T* new_value, D* volatile* dest) const { + // Allow derived to base conversion, and adding cv-qualifiers. + D* value = new_value; + PlatformOp()(value, dest); + } +}; + +// Handle store for types that have a translator. +// +// All the involved types must be identical. +// +// This translates the original call into a call on the decayed +// arguments. +template +struct Atomic::StoreImpl< + T, T, + PlatformOp, + typename EnableIf::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + void operator()(T new_value, T volatile* dest) const { + typedef PrimitiveConversions::Translate Translator; + typedef typename Translator::Decayed Decayed; + STATIC_ASSERT(sizeof(T) == sizeof(Decayed)); + PlatformOp()(Translator::decay(new_value), + reinterpret_cast(dest)); + } +}; + +// Default implementation of atomic store if a specific platform +// does not provide a specialization for a certain size class. +// For increased safety, the default implementation only allows +// storing types that are pointer sized or smaller. If a platform still +// supports wide atomics, then it has to use specialization +// of Atomic::PlatformStore for that wider size class. +template +struct Atomic::PlatformStore VALUE_OBJ_CLASS_SPEC { + template + void operator()(T new_value, + T volatile* dest) const { + STATIC_ASSERT(sizeof(T) <= sizeof(void*)); // wide atomics need specialization + (void)const_cast(*dest = new_value); + } +}; + // Define FetchAndAdd and AddAndFetch helper classes before including // platform file, which may use these as base classes, requiring they // be complete. @@ -312,6 +501,39 @@ struct Atomic::AddAndFetch VALUE_OBJ_CLASS_SPEC { D operator()(I add_value, D volatile* dest) const; }; +template +inline void Atomic::inc(D volatile* dest) { + STATIC_ASSERT(IsPointer::value || IsIntegral::value); + typedef typename Conditional::value, ptrdiff_t, D>::type I; + Atomic::add(I(1), dest); +} + +template +inline void Atomic::dec(D volatile* dest) { + STATIC_ASSERT(IsPointer::value || IsIntegral::value); + typedef typename Conditional::value, ptrdiff_t, D>::type I; + // Assumes two's complement integer representation. + #pragma warning(suppress: 4146) + Atomic::add(I(-1), dest); +} + +template +inline D Atomic::sub(I sub_value, D volatile* dest) { + STATIC_ASSERT(IsPointer::value || IsIntegral::value); + STATIC_ASSERT(IsIntegral::value); + // If D is a pointer type, use [u]intptr_t as the addend type, + // matching signedness of I. Otherwise, use D as the addend type. + typedef typename Conditional::value, intptr_t, uintptr_t>::type PI; + typedef typename Conditional::value, PI, D>::type AddendType; + // Only allow conversions that can't change the value. + STATIC_ASSERT(IsSigned::value == IsSigned::value); + STATIC_ASSERT(sizeof(I) <= sizeof(AddendType)); + AddendType addend = sub_value; + // Assumes two's complement integer representation. + #pragma warning(suppress: 4146) // In case AddendType is not signed. + return Atomic::add(-addend, dest); +} + // Define the class before including platform file, which may specialize // the operator definition. No generic definition of specializations // of the operator template are provided, nor are there any generic @@ -337,6 +559,18 @@ struct Atomic::CmpxchgByteUsingInt VALUE_OBJ_CLASS_SPEC { cmpxchg_memory_order order) const; }; +// Define the class before including platform file, which may specialize +// the operator definition. No generic definition of specializations +// of the operator template are provided, nor are there any generic +// specializations of the class. The platform file is responsible for +// providing those. +template +struct Atomic::PlatformXchg VALUE_OBJ_CLASS_SPEC { + template + T operator()(T exchange_value, + T volatile* dest) const; +}; + // platform specific in-line definitions - must come before shared definitions #include OS_CPU_HEADER(atomic) @@ -348,6 +582,16 @@ struct Atomic::CmpxchgByteUsingInt VALUE_OBJ_CLASS_SPEC { #error size_t is not WORD_SIZE, interesting platform, but missing implementation here #endif +template +inline T Atomic::load(const volatile T* dest) { + return LoadImpl >()(dest); +} + +template +inline void Atomic::store(T store_value, volatile D* dest) { + StoreImpl >()(store_value, dest); +} + template inline D Atomic::add(I add_value, D volatile* dest) { return AddImpl()(add_value, dest); @@ -437,14 +681,6 @@ inline D Atomic::add_using_helper(Fn fn, I add_value, D volatile* dest) { reinterpret_cast(dest))); } -inline void Atomic::inc(volatile size_t* dest) { - inc_ptr((volatile intptr_t*) dest); -} - -inline void Atomic::dec(volatile size_t* dest) { - dec_ptr((volatile intptr_t*) dest); -} - template inline D Atomic::cmpxchg(T exchange_value, D volatile* dest, @@ -586,17 +822,75 @@ inline T Atomic::CmpxchgByteUsingInt::operator()(T exchange_value, return PrimitiveConversions::cast(cur_as_bytes[offset]); } -inline unsigned Atomic::xchg(unsigned int exchange_value, volatile unsigned int* dest) { - assert(sizeof(unsigned int) == sizeof(jint), "more work to do"); - return (unsigned int)Atomic::xchg((jint)exchange_value, (volatile jint*)dest); +// Handle xchg for integral and enum types. +// +// All the involved types must be identical. +template +struct Atomic::XchgImpl< + T, T, + typename EnableIf::value || IsRegisteredEnum::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(T exchange_value, T volatile* dest) const { + // Forward to the platform handler for the size of T. + return PlatformXchg()(exchange_value, dest); + } +}; + +// Handle xchg for pointer types. +// +// The exchange_value must be implicitly convertible to the +// destination's type; it must be type-correct to store the +// exchange_value in the destination. +template +struct Atomic::XchgImpl< + T*, D*, + typename EnableIf::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + D* operator()(T* exchange_value, D* volatile* dest) const { + // Allow derived to base conversion, and adding cv-qualifiers. + D* new_value = exchange_value; + return PlatformXchg()(new_value, dest); + } +}; + +// Handle xchg for types that have a translator. +// +// All the involved types must be identical. +// +// This translates the original call into a call on the decayed +// arguments, and returns the recovered result of that translated +// call. +template +struct Atomic::XchgImpl< + T, T, + typename EnableIf::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(T exchange_value, T volatile* dest) const { + typedef PrimitiveConversions::Translate Translator; + typedef typename Translator::Decayed Decayed; + STATIC_ASSERT(sizeof(T) == sizeof(Decayed)); + return Translator::recover( + xchg(Translator::decay(exchange_value), + reinterpret_cast(dest))); + } +}; + +template +inline T Atomic::xchg_using_helper(Fn fn, + T exchange_value, + T volatile* dest) { + STATIC_ASSERT(sizeof(Type) == sizeof(T)); + return PrimitiveConversions::cast( + fn(PrimitiveConversions::cast(exchange_value), + reinterpret_cast(dest))); } -inline void Atomic::inc(volatile jshort* dest) { - (void)add(jshort(1), dest); -} - -inline void Atomic::dec(volatile jshort* dest) { - (void)add(jshort(-1), dest); +template +inline D Atomic::xchg(T exchange_value, volatile D* dest) { + return XchgImpl()(exchange_value, dest); } #endif // SHARE_VM_RUNTIME_ATOMIC_HPP diff --git a/src/hotspot/share/runtime/biasedLocking.cpp b/src/hotspot/share/runtime/biasedLocking.cpp index 983f5ea52c0..4440b842ffd 100644 --- a/src/hotspot/share/runtime/biasedLocking.cpp +++ b/src/hotspot/share/runtime/biasedLocking.cpp @@ -35,6 +35,7 @@ #include "runtime/vframe.hpp" #include "runtime/vmThread.hpp" #include "runtime/vm_operations.hpp" +#include "trace/tracing.hpp" static bool _biased_locking_enabled = false; BiasedLockingCounters BiasedLocking::_counters; @@ -643,23 +644,43 @@ BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attem // stale epoch. ResourceMark rm; log_info(biasedlocking)("Revoking bias by walking my own stack:"); + EventBiasedLockSelfRevocation event; BiasedLocking::Condition cond = revoke_bias(obj(), false, false, (JavaThread*) THREAD); ((JavaThread*) THREAD)->set_cached_monitor_info(NULL); assert(cond == BIAS_REVOKED, "why not?"); + if (event.should_commit()) { + event.set_lockClass(k); + event.commit(); + } return cond; } else { + EventBiasedLockRevocation event; VM_RevokeBias revoke(&obj, (JavaThread*) THREAD); VMThread::execute(&revoke); + if (event.should_commit() && (revoke.status_code() != NOT_BIASED)) { + event.set_lockClass(k); + // Subtract 1 to match the id of events committed inside the safepoint + event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); + event.commit(); + } return revoke.status_code(); } } assert((heuristics == HR_BULK_REVOKE) || (heuristics == HR_BULK_REBIAS), "?"); + EventBiasedLockClassRevocation event; VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*) THREAD, (heuristics == HR_BULK_REBIAS), attempt_rebias); VMThread::execute(&bulk_revoke); + if (event.should_commit()) { + event.set_revokedClass(obj->klass()); + event.set_disableBiasing((heuristics != HR_BULK_REBIAS)); + // Subtract 1 to match the id of events committed inside the safepoint + event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); + event.commit(); + } return bulk_revoke.status_code(); } diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.cpp index f74b502ea5a..13d8498aa5e 100644 --- a/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.cpp @@ -64,7 +64,7 @@ Flag::Error AliasLevelConstraintFunc(intx value, bool verbose) { */ Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { int min_number_of_compiler_threads = 0; -#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) && !INCLUDE_JVMCI +#if !defined(COMPILER1) && !defined(COMPILER2) && !INCLUDE_JVMCI // case 1 #else if (!TieredCompilation || (TieredStopAtLevel < CompLevel_full_optimization)) { diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 9220e920875..9e14d5f166f 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -339,7 +339,6 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread } -#ifndef SHARK // Compute the caller frame based on the sender sp of stub_frame and stored frame sizes info. CodeBlob* cb = stub_frame.cb(); // Verify we have the right vframeArray @@ -359,9 +358,6 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread strcmp("Stub", cb->name()) == 0, "unexpected code blob: %s", cb->name()); #endif -#else - intptr_t* unpack_sp = stub_frame.sender(&dummy_map).unextended_sp(); -#endif // !SHARK // This is a guarantee instead of an assert because if vframe doesn't match // we will unpack the wrong deoptimized frame and wind up in strange places @@ -488,9 +484,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread frame_pcs[0] = deopt_sender.raw_pc(); -#ifndef SHARK assert(CodeCache::find_blob_unsafe(frame_pcs[0]) != NULL, "bad pc"); -#endif // SHARK #ifdef INCLUDE_JVMCI if (exceptionObject() != NULL) { @@ -1386,7 +1380,7 @@ address Deoptimization::deoptimize_for_missing_exception_handler(CompiledMethod* RegisterMap reg_map(thread, UseBiasedLocking); frame runtime_frame = thread->last_frame(); frame caller_frame = runtime_frame.sender(®_map); - assert(caller_frame.cb()->as_nmethod_or_null() == cm, "expect top frame nmethod"); + assert(caller_frame.cb()->as_compiled_method_or_null() == cm, "expect top frame compiled method"); Deoptimization::deoptimize(thread, caller_frame, ®_map, Deoptimization::Reason_not_compiled_exception_handler); MethodData* trap_mdo = get_method_data(thread, cm->method(), true); @@ -1449,7 +1443,7 @@ Deoptimization::get_method_data(JavaThread* thread, const methodHandle& m, return mdo; } -#if defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI +#if defined(COMPILER2) || INCLUDE_JVMCI void Deoptimization::load_class_by_index(const constantPoolHandle& constant_pool, int index, TRAPS) { // in case of an unresolved klass entry, load the class. if (constant_pool->tag_at(index).is_unresolved_klass()) { @@ -2366,7 +2360,7 @@ void Deoptimization::print_statistics() { if (xtty != NULL) xtty->tail("statistics"); } } -#else // COMPILER2 || SHARK || INCLUDE_JVMCI +#else // COMPILER2 || INCLUDE_JVMCI // Stubs for C1 only system. @@ -2402,4 +2396,4 @@ const char* Deoptimization::format_trap_state(char* buf, size_t buflen, return buf; } -#endif // COMPILER2 || SHARK || INCLUDE_JVMCI +#endif // COMPILER2 || INCLUDE_JVMCI diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index d31d022789b..1ae48bdedf9 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -627,16 +627,9 @@ void frame::print_C_frame(outputStream* st, char* buf, int buflen, address pc) { st->print(" " PTR_FORMAT, p2i(pc)); } - // function name - os::dll_address_to_function_name() may return confusing - // names if pc is within jvm.dll or libjvm.so, because JVM only has - // JVM_xxxx and a few other symbols in the dynamic symbol table. Do this - // only for native libraries. - if (!in_vm || Decoder::can_decode_C_frame_in_vm()) { - found = os::dll_address_to_function_name(pc, buf, buflen, &offset); - - if (found) { - st->print(" %s+0x%x", buf, offset); - } + found = os::dll_address_to_function_name(pc, buf, buflen, &offset); + if (found) { + st->print(" %s+0x%x", buf, offset); } } @@ -1122,10 +1115,6 @@ void frame::oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* ma oops_entry_do(f, map); } else if (CodeCache::contains(pc())) { oops_code_blob_do(f, cf, map); -#ifdef SHARK - } else if (is_fake_stub_frame()) { - // nothing to do -#endif // SHARK } else { ShouldNotReachHere(); } diff --git a/src/hotspot/share/runtime/frame.inline.hpp b/src/hotspot/share/runtime/frame.inline.hpp index ba942169bcd..e23b98b3cde 100644 --- a/src/hotspot/share/runtime/frame.inline.hpp +++ b/src/hotspot/share/runtime/frame.inline.hpp @@ -37,7 +37,6 @@ # include "entryFrame_zero.hpp" # include "fakeStubFrame_zero.hpp" # include "interpreterFrame_zero.hpp" -# include "sharkFrame_zero.hpp" #endif #include CPU_HEADER_INLINE(frame) diff --git a/src/hotspot/share/runtime/globals.cpp b/src/hotspot/share/runtime/globals.cpp index ca3486b9827..5ac9f55a880 100644 --- a/src/hotspot/share/runtime/globals.cpp +++ b/src/hotspot/share/runtime/globals.cpp @@ -50,9 +50,6 @@ #ifdef COMPILER2 #include "opto/c2_globals.hpp" #endif -#ifdef SHARK -#include "shark/shark_globals.hpp" -#endif RUNTIME_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ MATERIALIZE_PD_DEVELOPER_FLAG, \ @@ -578,7 +575,6 @@ void Flag::print_kind_and_origin(outputStream* st) { { KIND_C1, "C1" }, { KIND_C2, "C2" }, { KIND_ARCH, "ARCH" }, - { KIND_SHARK, "SHARK" }, { KIND_PLATFORM_DEPENDENT, "pd" }, { KIND_PRODUCT, "product" }, { KIND_MANAGEABLE, "manageable" }, @@ -754,14 +750,6 @@ const char* Flag::flag_error_str(Flag::Error error) { #define ARCH_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_DEVELOP) }, #define ARCH_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_NOT_PRODUCT) }, -#define SHARK_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_PRODUCT) }, -#define SHARK_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, -#define SHARK_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DIAGNOSTIC) }, -#define SHARK_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DIAGNOSTIC | Flag::KIND_PLATFORM_DEPENDENT) }, -#define SHARK_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DEVELOP) }, -#define SHARK_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, -#define SHARK_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_NOT_PRODUCT) }, - static Flag flagTable[] = { RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ RUNTIME_PD_DEVELOP_FLAG_STRUCT, \ @@ -840,18 +828,6 @@ static Flag flagTable[] = { IGNORE_CONSTRAINT, \ IGNORE_WRITEABLE) #endif // COMPILER2 -#ifdef SHARK - SHARK_FLAGS(SHARK_DEVELOP_FLAG_STRUCT, \ - SHARK_PD_DEVELOP_FLAG_STRUCT, \ - SHARK_PRODUCT_FLAG_STRUCT, \ - SHARK_PD_PRODUCT_FLAG_STRUCT, \ - SHARK_DIAGNOSTIC_FLAG_STRUCT, \ - SHARK_PD_DIAGNOSTIC_FLAG_STRUCT, \ - SHARK_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) -#endif // SHARK ARCH_FLAGS(ARCH_DEVELOP_FLAG_STRUCT, \ ARCH_PRODUCT_FLAG_STRUCT, \ ARCH_DIAGNOSTIC_FLAG_STRUCT, \ diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 7e9dc8768f3..ddef624a3f7 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -63,13 +63,8 @@ #include CPU_HEADER(c2_globals) #include OS_HEADER(c2_globals) #endif -#ifdef SHARK -#ifdef ZERO -# include "shark_globals_zero.hpp" -#endif -#endif -#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) && !INCLUDE_JVMCI +#if !defined(COMPILER1) && !defined(COMPILER2) && !INCLUDE_JVMCI define_pd_global(bool, BackgroundCompilation, false); define_pd_global(bool, UseTLAB, false); define_pd_global(bool, CICompileOSR, false); @@ -147,13 +142,12 @@ struct Flag { KIND_C1 = 1 << 12, KIND_C2 = 1 << 13, KIND_ARCH = 1 << 14, - KIND_SHARK = 1 << 15, - KIND_LP64_PRODUCT = 1 << 16, - KIND_COMMERCIAL = 1 << 17, - KIND_JVMCI = 1 << 18, + KIND_LP64_PRODUCT = 1 << 15, + KIND_COMMERCIAL = 1 << 16, + KIND_JVMCI = 1 << 17, // set this bit if the flag was set on the command line - ORIG_COMMAND_LINE = 1 << 19, + ORIG_COMMAND_LINE = 1 << 18, KIND_MASK = ~(VALUE_ORIGIN_MASK | ORIG_COMMAND_LINE) }; @@ -592,8 +586,8 @@ public: range(8, 256) \ constraint(ObjectAlignmentInBytesConstraintFunc,AtParse) \ \ - product(bool, AssumeMP, false, \ - "Instruct the VM to assume multiple processors are available") \ + product(bool, AssumeMP, true, \ + "(Deprecated) Instruct the VM to assume multiple processors are available")\ \ /* UseMembar is theoretically a temp flag used for memory barrier */ \ /* removal testing. It was supposed to be removed before FCS but has */ \ @@ -2344,12 +2338,6 @@ public: range(30*K, max_uintx/BytesPerWord) \ constraint(InitialBootClassLoaderMetaspaceSizeConstraintFunc, AfterErgo)\ \ - product(bool, TraceYoungGenTime, false, \ - "Trace accumulated time for young collection") \ - \ - product(bool, TraceOldGenTime, false, \ - "Trace accumulated time for old collection") \ - \ product(bool, PrintHeapAtSIGBREAK, true, \ "Print heap layout in response to SIGBREAK") \ \ diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp index 4450d2cc2dd..2386744b15f 100644 --- a/src/hotspot/share/runtime/init.cpp +++ b/src/hotspot/share/runtime/init.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -58,6 +58,10 @@ void VM_Version_init(); void os_init_globals(); // depends on VM_Version_init, before universe_init void stubRoutines_init1(); jint universe_init(); // depends on codeCache_init and stubRoutines_init +#if INCLUDE_ALL_GCS +// depends on universe_init, must be before interpreter_init (currently only on SPARC) +void g1_barrier_stubs_init() NOT_SPARC({}); +#endif void interpreter_init(); // before any methods loaded void invocationCounter_init(); // before any methods loaded void marksweep_init(); @@ -112,7 +116,10 @@ jint init_globals() { if (status != JNI_OK) return status; - interpreter_init(); // before any methods loaded +#if INCLUDE_ALL_GCS + g1_barrier_stubs_init(); // depends on universe_init, must be before interpreter_init +#endif + interpreter_init(); // before any methods loaded invocationCounter_init(); // before any methods loaded marksweep_init(); accessFlags_init(); diff --git a/src/hotspot/share/runtime/jniHandles.cpp b/src/hotspot/share/runtime/jniHandles.cpp index 1a87c6a6212..2f5049fcd27 100644 --- a/src/hotspot/share/runtime/jniHandles.cpp +++ b/src/hotspot/share/runtime/jniHandles.cpp @@ -27,7 +27,6 @@ #include "logging/log.hpp" #include "memory/iterator.hpp" #include "oops/oop.inline.hpp" -#include "prims/jvmtiExport.hpp" #include "runtime/jniHandles.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" @@ -424,12 +423,6 @@ void JNIHandleBlock::weak_oops_do(BoolObjectClosure* is_alive, break; } } - - /* - * JVMTI data structures may also contain weak oops. The iteration of them - * is placed here so that we don't need to add it to each of the collectors. - */ - JvmtiExport::weak_oops_do(is_alive, f); } diff --git a/src/hotspot/share/runtime/mutex.cpp b/src/hotspot/share/runtime/mutex.cpp index b04d185bd8e..15dec651275 100644 --- a/src/hotspot/share/runtime/mutex.cpp +++ b/src/hotspot/share/runtime/mutex.cpp @@ -251,12 +251,6 @@ // // o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o - -// CASPTR() uses the canonical argument order that dominates in the literature. -// Our internal cmpxchg_ptr() uses a bastardized ordering to accommodate Sun .il templates. - -#define CASPTR(a, c, s) \ - intptr_t(Atomic::cmpxchg_ptr((void *)(s), (void *)(a), (void *)(c))) #define UNS(x) (uintptr_t(x)) #define TRACE(m) \ { \ @@ -268,6 +262,15 @@ } \ } +const intptr_t _LBIT = 1; + +// Endian-ness ... index of least-significant byte in SplitWord.Bytes[] +#ifdef VM_LITTLE_ENDIAN + #define _LSBINDEX 0 +#else + #define _LSBINDEX (sizeof(intptr_t)-1) +#endif + // Simplistic low-quality Marsaglia SHIFT-XOR RNG. // Bijective except for the trailing mask operation. // Useful for spin loops as the compiler can't optimize it away. @@ -297,7 +300,7 @@ int Monitor::TryLock() { intptr_t v = _LockWord.FullWord; for (;;) { if ((v & _LBIT) != 0) return 0; - const intptr_t u = CASPTR(&_LockWord, v, v|_LBIT); + const intptr_t u = Atomic::cmpxchg(v|_LBIT, &_LockWord.FullWord, v); if (v == u) return 1; v = u; } @@ -307,12 +310,12 @@ int Monitor::TryFast() { // Optimistic fast-path form ... // Fast-path attempt for the common uncontended case. // Avoid RTS->RTO $ coherence upgrade on typical SMP systems. - intptr_t v = CASPTR(&_LockWord, 0, _LBIT); // agro ... + intptr_t v = Atomic::cmpxchg(_LBIT, &_LockWord.FullWord, (intptr_t)0); // agro ... if (v == 0) return 1; for (;;) { if ((v & _LBIT) != 0) return 0; - const intptr_t u = CASPTR(&_LockWord, v, v|_LBIT); + const intptr_t u = Atomic::cmpxchg(v|_LBIT, &_LockWord.FullWord, v); if (v == u) return 1; v = u; } @@ -350,7 +353,7 @@ int Monitor::TrySpin(Thread * const Self) { for (;;) { intptr_t v = _LockWord.FullWord; if ((v & _LBIT) == 0) { - if (CASPTR (&_LockWord, v, v|_LBIT) == v) { + if (Atomic::cmpxchg (v|_LBIT, &_LockWord.FullWord, v) == v) { return 1; } continue; @@ -419,13 +422,13 @@ inline int Monitor::AcquireOrPush(ParkEvent * ESelf) { intptr_t v = _LockWord.FullWord; for (;;) { if ((v & _LBIT) == 0) { - const intptr_t u = CASPTR(&_LockWord, v, v|_LBIT); + const intptr_t u = Atomic::cmpxchg(v|_LBIT, &_LockWord.FullWord, v); if (u == v) return 1; // indicate acquired v = u; } else { // Anticipate success ... ESelf->ListNext = (ParkEvent *)(v & ~_LBIT); - const intptr_t u = CASPTR(&_LockWord, v, intptr_t(ESelf)|_LBIT); + const intptr_t u = Atomic::cmpxchg(intptr_t(ESelf)|_LBIT, &_LockWord.FullWord, v); if (u == v) return 0; // indicate pushed onto cxq v = u; } @@ -463,7 +466,7 @@ void Monitor::ILock(Thread * Self) { OrderAccess::fence(); // Optional optimization ... try barging on the inner lock - if ((NativeMonitorFlags & 32) && CASPTR (&_OnDeck, NULL, UNS(ESelf)) == 0) { + if ((NativeMonitorFlags & 32) && Atomic::cmpxchg(ESelf, &_OnDeck, (ParkEvent*)NULL) == NULL) { goto OnDeck_LOOP; } @@ -474,7 +477,7 @@ void Monitor::ILock(Thread * Self) { // Only the OnDeck thread can try to acquire -- contend for -- the lock. // CONSIDER: use Self->OnDeck instead of m->OnDeck. // Deschedule Self so that others may run. - while (OrderAccess::load_ptr_acquire(&_OnDeck) != ESelf) { + while (OrderAccess::load_acquire(&_OnDeck) != ESelf) { ParkCommon(ESelf, 0); } @@ -526,7 +529,7 @@ void Monitor::IUnlock(bool RelaxAssert) { // Note that the OrderAccess::storeload() fence that appears after unlock store // provides for progress conditions and succession and is _not related to exclusion // safety or lock release consistency. - OrderAccess::release_store(&_LockWord.Bytes[_LSBINDEX], 0); // drop outer lock + OrderAccess::release_store(&_LockWord.Bytes[_LSBINDEX], jbyte(0)); // drop outer lock OrderAccess::storeload(); ParkEvent * const w = _OnDeck; // raw load as we will just return if non-NULL @@ -570,7 +573,7 @@ void Monitor::IUnlock(bool RelaxAssert) { // Unlike a normal lock, however, the exiting thread "locks" OnDeck, // picks a successor and marks that thread as OnDeck. That successor // thread will then clear OnDeck once it eventually acquires the outer lock. - if (CASPTR (&_OnDeck, NULL, _LBIT) != UNS(NULL)) { + if (Atomic::cmpxchg((ParkEvent*)_LBIT, &_OnDeck, (ParkEvent*)NULL) != NULL) { return; } @@ -585,14 +588,14 @@ void Monitor::IUnlock(bool RelaxAssert) { assert(RelaxAssert || w != Thread::current()->_MutexEvent, "invariant"); _EntryList = w->ListNext; // as a diagnostic measure consider setting w->_ListNext = BAD - assert(UNS(_OnDeck) == _LBIT, "invariant"); + assert(intptr_t(_OnDeck) == _LBIT, "invariant"); // Pass OnDeck role to w, ensuring that _EntryList has been set first. // w will clear _OnDeck once it acquires the outer lock. // Note that once we set _OnDeck that thread can acquire the mutex, proceed // with its critical section and then enter this code to unlock the mutex. So // you can have multiple threads active in IUnlock at the same time. - OrderAccess::release_store_ptr(&_OnDeck, w); + OrderAccess::release_store(&_OnDeck, w); // Another optional optimization ... // For heavily contended locks it's not uncommon that some other @@ -616,7 +619,7 @@ void Monitor::IUnlock(bool RelaxAssert) { for (;;) { // optional optimization - if locked, the owner is responsible for succession if (cxq & _LBIT) goto Punt; - const intptr_t vfy = CASPTR(&_LockWord, cxq, cxq & _LBIT); + const intptr_t vfy = Atomic::cmpxchg(cxq & _LBIT, &_LockWord.FullWord, cxq); if (vfy == cxq) break; cxq = vfy; // Interference - LockWord changed - Just retry @@ -652,7 +655,7 @@ void Monitor::IUnlock(bool RelaxAssert) { // A thread could have added itself to cxq since this thread previously checked. // Detect and recover by refetching cxq. Punt: - assert(UNS(_OnDeck) == _LBIT, "invariant"); + assert(intptr_t(_OnDeck) == _LBIT, "invariant"); _OnDeck = NULL; // Release inner lock. OrderAccess::storeload(); // Dekker duality - pivot point @@ -693,7 +696,7 @@ bool Monitor::notify() { const intptr_t v = _LockWord.FullWord; assert((v & 0xFF) == _LBIT, "invariant"); nfy->ListNext = (ParkEvent *)(v & ~_LBIT); - if (CASPTR (&_LockWord, v, UNS(nfy)|_LBIT) == v) break; + if (Atomic::cmpxchg(intptr_t(nfy)|_LBIT, &_LockWord.FullWord, v) == v) break; // interference - _LockWord changed -- just retry } // Note that setting Notified before pushing nfy onto the cxq is @@ -840,7 +843,7 @@ int Monitor::IWait(Thread * Self, jlong timo) { // ESelf is now on the cxq, EntryList or at the OnDeck position. // The following fragment is extracted from Monitor::ILock() for (;;) { - if (OrderAccess::load_ptr_acquire(&_OnDeck) == ESelf && TrySpin(Self)) break; + if (OrderAccess::load_acquire(&_OnDeck) == ESelf && TrySpin(Self)) break; ParkCommon(ESelf, 0); } assert(_OnDeck == ESelf, "invariant"); @@ -1058,7 +1061,7 @@ void Monitor::jvm_raw_lock() { // Only the OnDeck thread can try to acquire -- contend for -- the lock. // CONSIDER: use Self->OnDeck instead of m->OnDeck. for (;;) { - if (OrderAccess::load_ptr_acquire(&_OnDeck) == ESelf && TrySpin(NULL)) break; + if (OrderAccess::load_acquire(&_OnDeck) == ESelf && TrySpin(NULL)) break; ParkCommon(ESelf, 0); } diff --git a/src/hotspot/share/runtime/mutex.hpp b/src/hotspot/share/runtime/mutex.hpp index 2e46948e99d..a2a8041ee82 100644 --- a/src/hotspot/share/runtime/mutex.hpp +++ b/src/hotspot/share/runtime/mutex.hpp @@ -67,13 +67,6 @@ union SplitWord { // full-word with separately addressable LSB volatile jbyte Bytes [sizeof(intptr_t)] ; } ; -// Endian-ness ... index of least-significant byte in SplitWord.Bytes[] -#ifdef VM_LITTLE_ENDIAN - #define _LSBINDEX 0 -#else - #define _LSBINDEX (sizeof(intptr_t)-1) -#endif - class ParkEvent ; // See orderAccess.hpp. We assume throughout the VM that mutex lock and @@ -128,7 +121,6 @@ class Monitor : public CHeapObj { protected: // Monitor-Mutex metadata SplitWord _LockWord ; // Contention queue (cxq) colocated with Lock-byte - enum LockWordBits { _LBIT=1 } ; Thread * volatile _owner; // The owner of the lock // Consider sequestering _owner on its own $line // to aid future synchronization mechanisms. diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 8247bf2d5e2..1caeaa9265c 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -249,7 +249,7 @@ void ObjectMonitor::enter(TRAPS) { // and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors. Thread * const Self = THREAD; - void * cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL); + void * cur = Atomic::cmpxchg(Self, &_owner, (void*)NULL); if (cur == NULL) { // Either ASSERT _recursions == 0 or explicitly set _recursions = 0. assert(_recursions == 0, "invariant"); @@ -406,7 +406,7 @@ void ObjectMonitor::enter(TRAPS) { int ObjectMonitor::TryLock(Thread * Self) { void * own = _owner; if (own != NULL) return 0; - if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) { + if (Atomic::cmpxchg(Self, &_owner, (void*)NULL) == NULL) { // Either guarantee _recursions == 0 or set _recursions = 0. assert(_recursions == 0, "invariant"); assert(_owner == Self, "invariant"); @@ -476,7 +476,7 @@ void ObjectMonitor::EnterI(TRAPS) { ObjectWaiter * nxt; for (;;) { node._next = nxt = _cxq; - if (Atomic::cmpxchg_ptr(&node, &_cxq, nxt) == nxt) break; + if (Atomic::cmpxchg(&node, &_cxq, nxt) == nxt) break; // Interference - the CAS failed because _cxq changed. Just retry. // As an optional optimization we retry the lock. @@ -514,7 +514,7 @@ void ObjectMonitor::EnterI(TRAPS) { if ((SyncFlags & 16) == 0 && nxt == NULL && _EntryList == NULL) { // Try to assume the role of responsible thread for the monitor. // CONSIDER: ST vs CAS vs { if (Responsible==null) Responsible=Self } - Atomic::cmpxchg_ptr(Self, &_Responsible, NULL); + Atomic::cmpxchg(Self, &_Responsible, (Thread*)NULL); } // The lock might have been released while this thread was occupied queueing @@ -538,7 +538,7 @@ void ObjectMonitor::EnterI(TRAPS) { assert(_owner != Self, "invariant"); if ((SyncFlags & 2) && _Responsible == NULL) { - Atomic::cmpxchg_ptr(Self, &_Responsible, NULL); + Atomic::cmpxchg(Self, &_Responsible, (Thread*)NULL); } // park self @@ -795,7 +795,7 @@ void ObjectMonitor::UnlinkAfterAcquire(Thread *Self, ObjectWaiter *SelfNode) { ObjectWaiter * v = _cxq; assert(v != NULL, "invariant"); - if (v != SelfNode || Atomic::cmpxchg_ptr (SelfNode->_next, &_cxq, v) != v) { + if (v != SelfNode || Atomic::cmpxchg(SelfNode->_next, &_cxq, v) != v) { // The CAS above can fail from interference IFF a "RAT" arrived. // In that case Self must be in the interior and can no longer be // at the head of cxq. @@ -947,7 +947,7 @@ void ObjectMonitor::exit(bool not_suspended, TRAPS) { // in massive wasteful coherency traffic on classic SMP systems. // Instead, I use release_store(), which is implemented as just a simple // ST on x64, x86 and SPARC. - OrderAccess::release_store_ptr(&_owner, NULL); // drop the lock + OrderAccess::release_store(&_owner, (void*)NULL); // drop the lock OrderAccess::storeload(); // See if we need to wake a successor if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) { TEVENT(Inflated exit - simple egress); @@ -992,13 +992,13 @@ void ObjectMonitor::exit(bool not_suspended, TRAPS) { // to reacquire the lock the responsibility for ensuring succession // falls to the new owner. // - if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) { + if (Atomic::cmpxchg(THREAD, &_owner, (void*)NULL) != NULL) { return; } TEVENT(Exit - Reacquired); } else { if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) { - OrderAccess::release_store_ptr(&_owner, NULL); // drop the lock + OrderAccess::release_store(&_owner, (void*)NULL); // drop the lock OrderAccess::storeload(); // Ratify the previously observed values. if (_cxq == NULL || _succ != NULL) { @@ -1017,7 +1017,7 @@ void ObjectMonitor::exit(bool not_suspended, TRAPS) { // B. If the elements forming the EntryList|cxq are TSM // we could simply unpark() the lead thread and return // without having set _succ. - if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) { + if (Atomic::cmpxchg(THREAD, &_owner, (void*)NULL) != NULL) { TEVENT(Inflated exit - reacquired succeeded); return; } @@ -1052,7 +1052,7 @@ void ObjectMonitor::exit(bool not_suspended, TRAPS) { w = _cxq; for (;;) { assert(w != NULL, "Invariant"); - ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr(NULL, &_cxq, w); + ObjectWaiter * u = Atomic::cmpxchg((ObjectWaiter*)NULL, &_cxq, w); if (u == w) break; w = u; } @@ -1093,7 +1093,7 @@ void ObjectMonitor::exit(bool not_suspended, TRAPS) { w = _cxq; for (;;) { assert(w != NULL, "Invariant"); - ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr(NULL, &_cxq, w); + ObjectWaiter * u = Atomic::cmpxchg((ObjectWaiter*)NULL, &_cxq, w); if (u == w) break; w = u; } @@ -1146,7 +1146,7 @@ void ObjectMonitor::exit(bool not_suspended, TRAPS) { // The following loop is tantamount to: w = swap(&cxq, NULL) for (;;) { assert(w != NULL, "Invariant"); - ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr(NULL, &_cxq, w); + ObjectWaiter * u = Atomic::cmpxchg((ObjectWaiter*)NULL, &_cxq, w); if (u == w) break; w = u; } @@ -1279,7 +1279,7 @@ void ObjectMonitor::ExitEpilog(Thread * Self, ObjectWaiter * Wakee) { Wakee = NULL; // Drop the lock - OrderAccess::release_store_ptr(&_owner, NULL); + OrderAccess::release_store(&_owner, (void*)NULL); OrderAccess::fence(); // ST _owner vs LD in unpark() if (SafepointSynchronize::do_call_back()) { @@ -1688,7 +1688,7 @@ void ObjectMonitor::INotify(Thread * Self) { for (;;) { ObjectWaiter * front = _cxq; iterator->_next = front; - if (Atomic::cmpxchg_ptr(iterator, &_cxq, front) == front) { + if (Atomic::cmpxchg(iterator, &_cxq, front) == front) { break; } } @@ -1699,7 +1699,7 @@ void ObjectMonitor::INotify(Thread * Self) { ObjectWaiter * tail = _cxq; if (tail == NULL) { iterator->_next = NULL; - if (Atomic::cmpxchg_ptr(iterator, &_cxq, NULL) == NULL) { + if (Atomic::cmpxchg(iterator, &_cxq, (ObjectWaiter*)NULL) == NULL) { break; } } else { @@ -1980,7 +1980,7 @@ int ObjectMonitor::TrySpin(Thread * Self) { Thread * ox = (Thread *) _owner; if (ox == NULL) { - ox = (Thread *) Atomic::cmpxchg_ptr(Self, &_owner, NULL); + ox = (Thread*)Atomic::cmpxchg(Self, &_owner, (void*)NULL); if (ox == NULL) { // The CAS succeeded -- this thread acquired ownership // Take care of some bookkeeping to exit spin state. diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index 4895874cbac..484b99aa2da 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, 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 @@ -143,7 +143,7 @@ class ObjectMonitor { volatile markOop _header; // displaced object header word - mark void* volatile _object; // backward object pointer - strong root public: - ObjectMonitor * FreeNext; // Free list linkage + ObjectMonitor* FreeNext; // Free list linkage private: DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile markOop) + sizeof(void * volatile) + @@ -251,6 +251,7 @@ class ObjectMonitor { ((ObjectMonitor::f ## _offset_in_bytes()) - markOopDesc::monitor_value) markOop header() const; + volatile markOop* header_addr(); void set_header(markOop hdr); intptr_t is_busy() const { diff --git a/src/hotspot/share/runtime/objectMonitor.inline.hpp b/src/hotspot/share/runtime/objectMonitor.inline.hpp index da81322a988..951d6472e03 100644 --- a/src/hotspot/share/runtime/objectMonitor.inline.hpp +++ b/src/hotspot/share/runtime/objectMonitor.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, 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 @@ -36,6 +36,11 @@ inline markOop ObjectMonitor::header() const { return _header; } +inline volatile markOop* ObjectMonitor::header_addr() { + assert((intptr_t)this == (intptr_t)&_header, "sync code expects this"); + return &_header; +} + inline void ObjectMonitor::set_header(markOop hdr) { _header = hdr; } diff --git a/src/hotspot/share/runtime/orderAccess.hpp b/src/hotspot/share/runtime/orderAccess.hpp index f0970986437..592cba162ab 100644 --- a/src/hotspot/share/runtime/orderAccess.hpp +++ b/src/hotspot/share/runtime/orderAccess.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_RUNTIME_ORDERACCESS_HPP #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" // Memory Access Ordering Model // @@ -252,7 +253,7 @@ class ScopedFence : public ScopedFenceGeneral { void postfix() { ScopedFenceGeneral::postfix(); } }; -class OrderAccess : AllStatic { +class OrderAccess : private Atomic { public: // barriers static void loadload(); @@ -264,47 +265,14 @@ class OrderAccess : AllStatic { static void release(); static void fence(); - static jbyte load_acquire(const volatile jbyte* p); - static jshort load_acquire(const volatile jshort* p); - static jint load_acquire(const volatile jint* p); - static jlong load_acquire(const volatile jlong* p); - static jubyte load_acquire(const volatile jubyte* p); - static jushort load_acquire(const volatile jushort* p); - static juint load_acquire(const volatile juint* p); - static julong load_acquire(const volatile julong* p); - static jfloat load_acquire(const volatile jfloat* p); - static jdouble load_acquire(const volatile jdouble* p); + template + static T load_acquire(const volatile T* p); - static intptr_t load_ptr_acquire(const volatile intptr_t* p); - static void* load_ptr_acquire(const volatile void* p); + template + static void release_store(volatile D* p, T v); - static void release_store(volatile jbyte* p, jbyte v); - static void release_store(volatile jshort* p, jshort v); - static void release_store(volatile jint* p, jint v); - static void release_store(volatile jlong* p, jlong v); - static void release_store(volatile jubyte* p, jubyte v); - static void release_store(volatile jushort* p, jushort v); - static void release_store(volatile juint* p, juint v); - static void release_store(volatile julong* p, julong v); - static void release_store(volatile jfloat* p, jfloat v); - static void release_store(volatile jdouble* p, jdouble v); - - static void release_store_ptr(volatile intptr_t* p, intptr_t v); - static void release_store_ptr(volatile void* p, void* v); - - static void release_store_fence(volatile jbyte* p, jbyte v); - static void release_store_fence(volatile jshort* p, jshort v); - static void release_store_fence(volatile jint* p, jint v); - static void release_store_fence(volatile jlong* p, jlong v); - static void release_store_fence(volatile jubyte* p, jubyte v); - static void release_store_fence(volatile jushort* p, jushort v); - static void release_store_fence(volatile juint* p, juint v); - static void release_store_fence(volatile julong* p, julong v); - static void release_store_fence(volatile jfloat* p, jfloat v); - static void release_store_fence(volatile jdouble* p, jdouble v); - - static void release_store_ptr_fence(volatile intptr_t* p, intptr_t v); - static void release_store_ptr_fence(volatile void* p, void* v); + template + static void release_store_fence(volatile D* p, T v); private: // This is a helper that invokes the StubRoutines::fence_entry() @@ -313,45 +281,34 @@ class OrderAccess : AllStatic { static void StubRoutines_fence(); // Give platforms a variation point to specialize. - template static T specialized_load_acquire (const volatile T* p); - template static void specialized_release_store (volatile T* p, T v); - template static void specialized_release_store_fence(volatile T* p, T v); + template struct PlatformOrderedStore; + template struct PlatformOrderedLoad; template static void ordered_store(volatile FieldType* p, FieldType v); template static FieldType ordered_load(const volatile FieldType* p); +}; - static void store(volatile jbyte* p, jbyte v); - static void store(volatile jshort* p, jshort v); - static void store(volatile jint* p, jint v); - static void store(volatile jlong* p, jlong v); - static void store(volatile jdouble* p, jdouble v); - static void store(volatile jfloat* p, jfloat v); +// The following methods can be specialized using simple template specialization +// in the platform specific files for optimization purposes. Otherwise the +// generalized variant is used. - static jbyte load(const volatile jbyte* p); - static jshort load(const volatile jshort* p); - static jint load(const volatile jint* p); - static jlong load(const volatile jlong* p); - static jdouble load(const volatile jdouble* p); - static jfloat load(const volatile jfloat* p); +template +struct OrderAccess::PlatformOrderedStore VALUE_OBJ_CLASS_SPEC { + template + void operator()(T v, volatile T* p) const { + ordered_store(p, v); + } +}; - // The following store_fence methods are deprecated and will be removed - // when all repos conform to the new generalized OrderAccess. - static void store_fence(jbyte* p, jbyte v); - static void store_fence(jshort* p, jshort v); - static void store_fence(jint* p, jint v); - static void store_fence(jlong* p, jlong v); - static void store_fence(jubyte* p, jubyte v); - static void store_fence(jushort* p, jushort v); - static void store_fence(juint* p, juint v); - static void store_fence(julong* p, julong v); - static void store_fence(jfloat* p, jfloat v); - static void store_fence(jdouble* p, jdouble v); - - static void store_ptr_fence(intptr_t* p, intptr_t v); - static void store_ptr_fence(void** p, void* v); +template +struct OrderAccess::PlatformOrderedLoad VALUE_OBJ_CLASS_SPEC { + template + T operator()(const volatile T* p) const { + return ordered_load(p); + } }; #endif // SHARE_VM_RUNTIME_ORDERACCESS_HPP diff --git a/src/hotspot/share/runtime/orderAccess.inline.hpp b/src/hotspot/share/runtime/orderAccess.inline.hpp index 1fa2185dd45..b1c50bb3abb 100644 --- a/src/hotspot/share/runtime/orderAccess.inline.hpp +++ b/src/hotspot/share/runtime/orderAccess.inline.hpp @@ -26,14 +26,11 @@ #ifndef SHARE_VM_RUNTIME_ORDERACCESS_INLINE_HPP #define SHARE_VM_RUNTIME_ORDERACCESS_INLINE_HPP -#include "runtime/atomic.hpp" #include "runtime/orderAccess.hpp" #include "utilities/macros.hpp" #include OS_CPU_HEADER_INLINE(orderAccess) -#ifdef VM_HAS_GENERALIZED_ORDER_ACCESS - template<> inline void ScopedFenceGeneral::postfix() { OrderAccess::acquire(); } template<> inline void ScopedFenceGeneral::prefix() { OrderAccess::release(); } template<> inline void ScopedFenceGeneral::prefix() { OrderAccess::release(); } @@ -43,80 +40,27 @@ template<> inline void ScopedFenceGeneral::postfix() { OrderAcc template inline void OrderAccess::ordered_store(volatile FieldType* p, FieldType v) { ScopedFence f((void*)p); - store(p, v); + Atomic::store(v, p); } template inline FieldType OrderAccess::ordered_load(const volatile FieldType* p) { ScopedFence f((void*)p); - return load(p); + return Atomic::load(p); } -inline jbyte OrderAccess::load_acquire(const volatile jbyte* p) { return specialized_load_acquire(p); } -inline jshort OrderAccess::load_acquire(const volatile jshort* p) { return specialized_load_acquire(p); } -inline jint OrderAccess::load_acquire(const volatile jint* p) { return specialized_load_acquire(p); } -inline jlong OrderAccess::load_acquire(const volatile jlong* p) { return specialized_load_acquire(p); } -inline jfloat OrderAccess::load_acquire(const volatile jfloat* p) { return specialized_load_acquire(p); } -inline jdouble OrderAccess::load_acquire(const volatile jdouble* p) { return specialized_load_acquire(p); } -inline jubyte OrderAccess::load_acquire(const volatile jubyte* p) { return (jubyte) specialized_load_acquire((const volatile jbyte*)p); } -inline jushort OrderAccess::load_acquire(const volatile jushort* p) { return (jushort)specialized_load_acquire((const volatile jshort*)p); } -inline juint OrderAccess::load_acquire(const volatile juint* p) { return (juint) specialized_load_acquire((const volatile jint*)p); } -inline julong OrderAccess::load_acquire(const volatile julong* p) { return (julong) specialized_load_acquire((const volatile jlong*)p); } +template +inline T OrderAccess::load_acquire(const volatile T* p) { + return LoadImpl >()(p); +} -inline intptr_t OrderAccess::load_ptr_acquire(const volatile intptr_t* p) { return (intptr_t)specialized_load_acquire(p); } -inline void* OrderAccess::load_ptr_acquire(const volatile void* p) { return (void*)specialized_load_acquire((const volatile intptr_t*)p); } - -inline void OrderAccess::release_store(volatile jbyte* p, jbyte v) { specialized_release_store(p, v); } -inline void OrderAccess::release_store(volatile jshort* p, jshort v) { specialized_release_store(p, v); } -inline void OrderAccess::release_store(volatile jint* p, jint v) { specialized_release_store(p, v); } -inline void OrderAccess::release_store(volatile jlong* p, jlong v) { specialized_release_store(p, v); } -inline void OrderAccess::release_store(volatile jfloat* p, jfloat v) { specialized_release_store(p, v); } -inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { specialized_release_store(p, v); } -inline void OrderAccess::release_store(volatile jubyte* p, jubyte v) { specialized_release_store((volatile jbyte*) p, (jbyte) v); } -inline void OrderAccess::release_store(volatile jushort* p, jushort v) { specialized_release_store((volatile jshort*)p, (jshort)v); } -inline void OrderAccess::release_store(volatile juint* p, juint v) { specialized_release_store((volatile jint*) p, (jint) v); } -inline void OrderAccess::release_store(volatile julong* p, julong v) { specialized_release_store((volatile jlong*) p, (jlong) v); } - -inline void OrderAccess::release_store_ptr(volatile intptr_t* p, intptr_t v) { specialized_release_store(p, v); } -inline void OrderAccess::release_store_ptr(volatile void* p, void* v) { specialized_release_store((volatile intptr_t*)p, (intptr_t)v); } - -inline void OrderAccess::release_store_fence(volatile jbyte* p, jbyte v) { specialized_release_store_fence(p, v); } -inline void OrderAccess::release_store_fence(volatile jshort* p, jshort v) { specialized_release_store_fence(p, v); } -inline void OrderAccess::release_store_fence(volatile jint* p, jint v) { specialized_release_store_fence(p, v); } -inline void OrderAccess::release_store_fence(volatile jlong* p, jlong v) { specialized_release_store_fence(p, v); } -inline void OrderAccess::release_store_fence(volatile jfloat* p, jfloat v) { specialized_release_store_fence(p, v); } -inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { specialized_release_store_fence(p, v); } -inline void OrderAccess::release_store_fence(volatile jubyte* p, jubyte v) { specialized_release_store_fence((volatile jbyte*) p, (jbyte) v); } -inline void OrderAccess::release_store_fence(volatile jushort* p, jushort v) { specialized_release_store_fence((volatile jshort*)p, (jshort)v); } -inline void OrderAccess::release_store_fence(volatile juint* p, juint v) { specialized_release_store_fence((volatile jint*) p, (jint) v); } -inline void OrderAccess::release_store_fence(volatile julong* p, julong v) { specialized_release_store_fence((volatile jlong*) p, (jlong) v); } - -inline void OrderAccess::release_store_ptr_fence(volatile intptr_t* p, intptr_t v) { specialized_release_store_fence(p, v); } -inline void OrderAccess::release_store_ptr_fence(volatile void* p, void* v) { specialized_release_store_fence((volatile intptr_t*)p, (intptr_t)v); } - -// The following methods can be specialized using simple template specialization -// in the platform specific files for optimization purposes. Otherwise the -// generalized variant is used. -template inline T OrderAccess::specialized_load_acquire (const volatile T* p) { return ordered_load(p); } -template inline void OrderAccess::specialized_release_store (volatile T* p, T v) { ordered_store(p, v); } -template inline void OrderAccess::specialized_release_store_fence(volatile T* p, T v) { ordered_store(p, v); } - -// Generalized atomic volatile accesses valid in OrderAccess -// All other types can be expressed in terms of these. -inline void OrderAccess::store(volatile jbyte* p, jbyte v) { *p = v; } -inline void OrderAccess::store(volatile jshort* p, jshort v) { *p = v; } -inline void OrderAccess::store(volatile jint* p, jint v) { *p = v; } -inline void OrderAccess::store(volatile jlong* p, jlong v) { Atomic::store(v, p); } -inline void OrderAccess::store(volatile jdouble* p, jdouble v) { Atomic::store(jlong_cast(v), (volatile jlong*)p); } -inline void OrderAccess::store(volatile jfloat* p, jfloat v) { *p = v; } - -inline jbyte OrderAccess::load(const volatile jbyte* p) { return *p; } -inline jshort OrderAccess::load(const volatile jshort* p) { return *p; } -inline jint OrderAccess::load(const volatile jint* p) { return *p; } -inline jlong OrderAccess::load(const volatile jlong* p) { return Atomic::load(p); } -inline jdouble OrderAccess::load(const volatile jdouble* p) { return jdouble_cast(Atomic::load((const volatile jlong*)p)); } -inline jfloat OrderAccess::load(const volatile jfloat* p) { return *p; } - -#endif // VM_HAS_GENERALIZED_ORDER_ACCESS +template +inline void OrderAccess::release_store(volatile D* p, T v) { + StoreImpl >()(v, p); +} +template +inline void OrderAccess::release_store_fence(volatile D* p, T v) { + StoreImpl >()(v, p); +} #endif // SHARE_VM_RUNTIME_ORDERACCESS_INLINE_HPP diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index d5fbca9192d..b29c0c3d03a 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -213,7 +213,7 @@ class os: AllStatic { // the bootstrap routine for the stub generator needs to check // the processor count directly and leave the bootstrap routine // in place until called after initialization has ocurred. - return (_processor_count != 1) || AssumeMP; + return AssumeMP || (_processor_count != 1); } static julong available_memory(); static julong physical_memory(); diff --git a/src/hotspot/share/runtime/perfMemory.cpp b/src/hotspot/share/runtime/perfMemory.cpp index d662827f683..58868d22706 100644 --- a/src/hotspot/share/runtime/perfMemory.cpp +++ b/src/hotspot/share/runtime/perfMemory.cpp @@ -53,6 +53,7 @@ char* PerfMemory::_top = NULL; size_t PerfMemory::_capacity = 0; jint PerfMemory::_initialized = false; PerfDataPrologue* PerfMemory::_prologue = NULL; +bool PerfMemory::_destroyed = false; void perfMemory_init() { @@ -64,7 +65,7 @@ void perfMemory_init() { void perfMemory_exit() { if (!UsePerfData) return; - if (!PerfMemory::is_initialized()) return; + if (!PerfMemory::is_usable()) return; // Only destroy PerfData objects if we're at a safepoint and the // StatSampler is not active. Otherwise, we risk removing PerfData @@ -88,7 +89,7 @@ void perfMemory_exit() { void PerfMemory::initialize() { - if (_prologue != NULL) + if (is_initialized()) // initialization already performed return; @@ -160,7 +161,7 @@ void PerfMemory::initialize() { void PerfMemory::destroy() { - if (_prologue == NULL) return; + if (!is_usable()) return; if (_start != NULL && _prologue->overflow != 0) { @@ -196,11 +197,7 @@ void PerfMemory::destroy() { delete_memory_region(); } - _start = NULL; - _end = NULL; - _top = NULL; - _prologue = NULL; - _capacity = 0; + _destroyed = true; } // allocate an aligned block of memory from the PerfData memory @@ -213,7 +210,7 @@ char* PerfMemory::alloc(size_t size) { MutexLocker ml(PerfDataMemAlloc_lock); - assert(_prologue != NULL, "called before initialization"); + assert(is_usable(), "called before init or after destroy"); // check that there is enough memory for this request if ((_top + size) >= _end) { @@ -238,6 +235,8 @@ char* PerfMemory::alloc(size_t size) { void PerfMemory::mark_updated() { if (!UsePerfData) return; + assert(is_usable(), "called before init or after destroy"); + _prologue->mod_time_stamp = os::elapsed_counter(); } @@ -268,3 +267,7 @@ char* PerfMemory::get_perfdata_file_path() { return dest_file; } + +bool PerfMemory::is_initialized() { + return OrderAccess::load_acquire(&_initialized) != 0; +} diff --git a/src/hotspot/share/runtime/perfMemory.hpp b/src/hotspot/share/runtime/perfMemory.hpp index 07e119ef8f8..c0684ca9422 100644 --- a/src/hotspot/share/runtime/perfMemory.hpp +++ b/src/hotspot/share/runtime/perfMemory.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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 @@ -113,6 +113,7 @@ static const size_t UINT_CHARS = 10; */ class PerfMemory : AllStatic { friend class VMStructs; + friend class PerfMemoryTest; private: static char* _start; static char* _end; @@ -120,6 +121,7 @@ class PerfMemory : AllStatic { static size_t _capacity; static PerfDataPrologue* _prologue; static jint _initialized; + static bool _destroyed; static void create_memory_region(size_t sizep); static void delete_memory_region(); @@ -135,7 +137,9 @@ class PerfMemory : AllStatic { static char* end() { return _end; } static size_t used() { return (size_t) (_top - _start); } static size_t capacity() { return _capacity; } - static bool is_initialized() { return _initialized != 0; } + static bool is_initialized(); + static bool is_destroyed() { return _destroyed; } + static bool is_usable() { return is_initialized() && !is_destroyed(); } static bool contains(char* addr) { return ((_start != NULL) && (addr >= _start) && (addr < _end)); } diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index 91d9bce8077..505803b2c6e 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -63,10 +63,6 @@ #include "trace/traceMacros.hpp" #include "utilities/events.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc/cms/concurrentMarkSweepThread.hpp" -#include "gc/g1/suspendibleThreadSet.hpp" -#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_globals.hpp" #endif @@ -94,15 +90,7 @@ void SafepointSynchronize::begin() { _ts_of_current_safepoint = tty->time_stamp().seconds(); } -#if INCLUDE_ALL_GCS - if (UseConcMarkSweepGC) { - // In the future we should investigate whether CMS can use the - // more-general mechanism below. DLD (01/05). - ConcurrentMarkSweepThread::synchronize(false); - } else if (UseG1GC) { - SuspendibleThreadSet::synchronize(); - } -#endif // INCLUDE_ALL_GCS + Universe::heap()->safepoint_synchronize_begin(); // By getting the Threads_lock, we assure that no threads are about to start or // exit. It is released again in SafepointSynchronize::end(). @@ -333,7 +321,8 @@ void SafepointSynchronize::begin() { } if (sync_event.should_commit()) { - sync_event.set_safepointId(safepoint_counter()); + // Group this event together with the ones committed after the counter is increased + sync_event.set_safepointId(safepoint_counter() + 1); sync_event.set_initialThreadCount(initial_running); sync_event.set_runningThreadCount(_waiting_to_block); sync_event.set_iterations(iterations); @@ -511,14 +500,7 @@ void SafepointSynchronize::end() { Threads_lock->unlock(); } -#if INCLUDE_ALL_GCS - // If there are any concurrent GC threads resume them. - if (UseConcMarkSweepGC) { - ConcurrentMarkSweepThread::desynchronize(false); - } else if (UseG1GC) { - SuspendibleThreadSet::desynchronize(); - } -#endif // INCLUDE_ALL_GCS + Universe::heap()->safepoint_synchronize_end(); // record this time so VMThread can keep track how much time has elapsed // since last safepoint. _end_of_last_safepoint = os::javaTimeMillis(); @@ -581,7 +563,7 @@ public: void work(uint worker_id) { // All threads deflate monitors and mark nmethods (if necessary). - Threads::parallel_java_threads_do(&_cleanup_threads_cl); + Threads::possibly_parallel_threads_do(true, &_cleanup_threads_cl); if (!_subtasks.is_task_claimed(SafepointSynchronize::SAFEPOINT_CLEANUP_DEFLATE_MONITORS)) { const char* name = "deflating idle monitors"; diff --git a/src/hotspot/share/runtime/sharedRuntimeTrans.cpp b/src/hotspot/share/runtime/sharedRuntimeTrans.cpp index 3b8c8a3010b..1e9fcceb3d9 100644 --- a/src/hotspot/share/runtime/sharedRuntimeTrans.cpp +++ b/src/hotspot/share/runtime/sharedRuntimeTrans.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, 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,7 +23,7 @@ */ #include "precompiled.hpp" -#include "prims/jni.h" +#include "jni.h" #include "runtime/interfaceSupport.hpp" #include "runtime/sharedRuntime.hpp" diff --git a/src/hotspot/share/runtime/sharedRuntimeTrig.cpp b/src/hotspot/share/runtime/sharedRuntimeTrig.cpp index 8acd7401585..2f5c173e54e 100644 --- a/src/hotspot/share/runtime/sharedRuntimeTrig.cpp +++ b/src/hotspot/share/runtime/sharedRuntimeTrig.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, 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,7 +23,7 @@ */ #include "precompiled.hpp" -#include "prims/jni.h" +#include "jni.h" #include "runtime/interfaceSupport.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/sharedRuntimeMath.hpp" diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index 4c0e9a1c2c0..d851b253aa5 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -59,11 +59,10 @@ address StubRoutines::_throw_delayed_StackOverflowError_entry = NULL; jint StubRoutines::_verify_oop_count = 0; address StubRoutines::_verify_oop_subroutine_entry = NULL; address StubRoutines::_atomic_xchg_entry = NULL; -address StubRoutines::_atomic_xchg_ptr_entry = NULL; +address StubRoutines::_atomic_xchg_long_entry = NULL; address StubRoutines::_atomic_store_entry = NULL; address StubRoutines::_atomic_store_ptr_entry = NULL; address StubRoutines::_atomic_cmpxchg_entry = NULL; -address StubRoutines::_atomic_cmpxchg_ptr_entry = NULL; address StubRoutines::_atomic_cmpxchg_byte_entry = NULL; address StubRoutines::_atomic_cmpxchg_long_entry = NULL; address StubRoutines::_atomic_add_entry = NULL; @@ -382,14 +381,12 @@ static void gen_arraycopy_barrier_pre(oop* dest, size_t count, bool dest_uniniti assert(count != 0, "count should be non-zero"); assert(count <= (size_t)max_intx, "count too large"); BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->has_write_ref_array_pre_opt(), "Must have pre-barrier opt"); bs->write_ref_array_pre(dest, (int)count, dest_uninitialized); } static void gen_arraycopy_barrier(oop* dest, size_t count) { assert(count != 0, "count should be non-zero"); BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt"); bs->write_ref_array((HeapWord*)dest, count); } diff --git a/src/hotspot/share/runtime/stubRoutines.hpp b/src/hotspot/share/runtime/stubRoutines.hpp index 067a22fec4b..25884a86b90 100644 --- a/src/hotspot/share/runtime/stubRoutines.hpp +++ b/src/hotspot/share/runtime/stubRoutines.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -101,11 +101,10 @@ class StubRoutines: AllStatic { static address _throw_delayed_StackOverflowError_entry; static address _atomic_xchg_entry; - static address _atomic_xchg_ptr_entry; + static address _atomic_xchg_long_entry; static address _atomic_store_entry; static address _atomic_store_ptr_entry; static address _atomic_cmpxchg_entry; - static address _atomic_cmpxchg_ptr_entry; static address _atomic_cmpxchg_byte_entry; static address _atomic_cmpxchg_long_entry; static address _atomic_add_entry; @@ -276,11 +275,10 @@ class StubRoutines: AllStatic { static address throw_delayed_StackOverflowError_entry() { return _throw_delayed_StackOverflowError_entry; } static address atomic_xchg_entry() { return _atomic_xchg_entry; } - static address atomic_xchg_ptr_entry() { return _atomic_xchg_ptr_entry; } + static address atomic_xchg_long_entry() { return _atomic_xchg_long_entry; } static address atomic_store_entry() { return _atomic_store_entry; } static address atomic_store_ptr_entry() { return _atomic_store_ptr_entry; } static address atomic_cmpxchg_entry() { return _atomic_cmpxchg_entry; } - static address atomic_cmpxchg_ptr_entry() { return _atomic_cmpxchg_ptr_entry; } static address atomic_cmpxchg_byte_entry() { return _atomic_cmpxchg_byte_entry; } static address atomic_cmpxchg_long_entry() { return _atomic_cmpxchg_long_entry; } static address atomic_add_entry() { return _atomic_add_entry; } diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 096b43eedcd..d54b0d8b30a 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -111,9 +111,7 @@ int dtrace_waited_probe(ObjectMonitor* monitor, Handle obj, Thread* thr) { static volatile intptr_t gInflationLocks[NINFLATIONLOCKS]; // global list of blocks of monitors -// gBlockList is really PaddedEnd *, but we don't -// want to expose the PaddedEnd template more than necessary. -ObjectMonitor * volatile ObjectSynchronizer::gBlockList = NULL; +PaddedEnd * volatile ObjectSynchronizer::gBlockList = NULL; // global monitor free list ObjectMonitor * volatile ObjectSynchronizer::gFreeList = NULL; // global monitor in-use list, for moribund threads, @@ -241,7 +239,7 @@ bool ObjectSynchronizer::quick_enter(oop obj, Thread * Self, lock->set_displaced_header(markOopDesc::unused_mark()); if (owner == NULL && - Atomic::cmpxchg_ptr(Self, &(m->_owner), NULL) == NULL) { + Atomic::cmpxchg(Self, &(m->_owner), (void*)NULL) == NULL) { assert(m->_recursions == 0, "invariant"); assert(m->_owner == Self, "invariant"); return true; @@ -802,7 +800,7 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread * Self, oop obj) { hash = get_next_hash(Self, obj); temp = mark->copy_set_hash(hash); // merge hash code into header assert(temp->is_neutral(), "invariant"); - test = (markOop) Atomic::cmpxchg_ptr(temp, monitor, mark); + test = Atomic::cmpxchg(temp, monitor->header_addr(), mark); if (test != mark) { // The only update to the header in the monitor (outside GC) // is install the hash code. If someone add new usage of @@ -939,8 +937,7 @@ JavaThread* ObjectSynchronizer::get_lock_owner(Handle h_obj, bool doLock) { // Visitors ... void ObjectSynchronizer::monitors_iterate(MonitorClosure* closure) { - PaddedEnd * block = - (PaddedEnd *)OrderAccess::load_ptr_acquire(&gBlockList); + PaddedEnd * block = OrderAccess::load_acquire(&gBlockList); while (block != NULL) { assert(block->object() == CHAINMARKER, "must be a block header"); for (int i = _BLOCKSIZE - 1; i > 0; i--) { @@ -955,9 +952,9 @@ void ObjectSynchronizer::monitors_iterate(MonitorClosure* closure) { } // Get the next block in the block list. -static inline ObjectMonitor* next(ObjectMonitor* block) { +static inline PaddedEnd* next(PaddedEnd* block) { assert(block->object() == CHAINMARKER, "must be a block header"); - block = block->FreeNext; + block = (PaddedEnd*) block->FreeNext; assert(block == NULL || block->object() == CHAINMARKER, "must be a block header"); return block; } @@ -991,9 +988,8 @@ void ObjectSynchronizer::oops_do(OopClosure* f) { void ObjectSynchronizer::global_oops_do(OopClosure* f) { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); - PaddedEnd * block = - (PaddedEnd *)OrderAccess::load_ptr_acquire(&gBlockList); - for (; block != NULL; block = (PaddedEnd *)next(block)) { + PaddedEnd * block = OrderAccess::load_acquire(&gBlockList); + for (; block != NULL; block = next(block)) { assert(block->object() == CHAINMARKER, "must be a block header"); for (int i = 1; i < _BLOCKSIZE; i++) { ObjectMonitor* mid = (ObjectMonitor *)&block[i]; @@ -1232,7 +1228,7 @@ ObjectMonitor* ObjectSynchronizer::omAlloc(Thread * Self) { temp[0].FreeNext = gBlockList; // There are lock-free uses of gBlockList so make sure that // the previous stores happen before we update gBlockList. - OrderAccess::release_store_ptr(&gBlockList, temp); + OrderAccess::release_store(&gBlockList, temp); // Add the new string of objectMonitors to the global free list temp[_BLOCKSIZE - 1].FreeNext = gFreeList; @@ -1734,9 +1730,8 @@ void ObjectSynchronizer::deflate_idle_monitors(DeflateMonitorCounters* counters) } } else { - PaddedEnd * block = - (PaddedEnd *)OrderAccess::load_ptr_acquire(&gBlockList); - for (; block != NULL; block = (PaddedEnd *)next(block)) { + PaddedEnd * block = OrderAccess::load_acquire(&gBlockList); + for (; block != NULL; block = next(block)) { // Iterate over all extant monitors - Scavenge all idle monitors. assert(block->object() == CHAINMARKER, "must be a block header"); counters->nInCirculation += _BLOCKSIZE; @@ -1969,12 +1964,10 @@ void ObjectSynchronizer::sanity_checks(const bool verbose, // the list of extant blocks without taking a lock. int ObjectSynchronizer::verify_objmon_isinpool(ObjectMonitor *monitor) { - PaddedEnd * block = - (PaddedEnd *)OrderAccess::load_ptr_acquire(&gBlockList); + PaddedEnd * block = OrderAccess::load_acquire(&gBlockList); while (block != NULL) { assert(block->object() == CHAINMARKER, "must be a block header"); - if (monitor > (ObjectMonitor *)&block[0] && - monitor < (ObjectMonitor *)&block[_BLOCKSIZE]) { + if (monitor > &block[0] && monitor < &block[_BLOCKSIZE]) { address mon = (address)monitor; address blk = (address)block; size_t diff = mon - blk; diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index eb3bc268b81..ba3ac60a267 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_VM_RUNTIME_SYNCHRONIZER_HPP #define SHARE_VM_RUNTIME_SYNCHRONIZER_HPP +#include "memory/padded.hpp" #include "oops/markOop.hpp" #include "runtime/basicLock.hpp" #include "runtime/handles.hpp" @@ -159,9 +160,7 @@ class ObjectSynchronizer : AllStatic { private: enum { _BLOCKSIZE = 128 }; // global list of blocks of monitors - // gBlockList is really PaddedEnd *, but we don't - // want to expose the PaddedEnd template more than necessary. - static ObjectMonitor * volatile gBlockList; + static PaddedEnd * volatile gBlockList; // global monitor free list static ObjectMonitor * volatile gFreeList; // global monitor in-use list, for moribund threads, diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index b1e7da21c7f..991dce7505f 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -3263,6 +3263,9 @@ CompilerThread::CompilerThread(CompileQueue* queue, _buffer_blob = NULL; _compiler = NULL; + // Compiler uses resource area for compilation, let's bias it to mtCompiler + resource_area()->bias_to(mtCompiler); + #ifndef PRODUCT _ideal_graph_printer = NULL; #endif @@ -3346,20 +3349,17 @@ void Threads::threads_do(ThreadClosure* tc) { // If CompilerThreads ever become non-JavaThreads, add them here } -void Threads::parallel_java_threads_do(ThreadClosure* tc) { +void Threads::possibly_parallel_threads_do(bool is_par, ThreadClosure* tc) { int cp = Threads::thread_claim_parity(); ALL_JAVA_THREADS(p) { - if (p->claim_oops_do(true, cp)) { + if (p->claim_oops_do(is_par, cp)) { tc->do_thread(p); } } - // Thread claiming protocol requires us to claim the same interesting - // threads on all paths. Notably, Threads::possibly_parallel_threads_do - // claims all Java threads *and* the VMThread. To avoid breaking the - // claiming protocol, we have to claim VMThread on this path too, even - // if we do not apply the closure to the VMThread. VMThread* vmt = VMThread::vm_thread(); - (void)vmt->claim_oops_do(true, cp); + if (vmt->claim_oops_do(is_par, cp)) { + tc->do_thread(vmt); + } } // The system initialization in the library has three phases. @@ -3724,7 +3724,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { } // initialize compiler(s) -#if defined(COMPILER1) || defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI +#if defined(COMPILER1) || defined(COMPILER2) || INCLUDE_JVMCI CompileBroker::compilation_init(CHECK_JNI_ERR); #endif @@ -3748,8 +3748,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // Final system initialization including security manager and system class loader call_initPhase3(CHECK_JNI_ERR); - // cache the system class loader - SystemDictionary::compute_java_system_loader(CHECK_(JNI_ERR)); + // cache the system and platform class loaders + SystemDictionary::compute_java_loaders(CHECK_JNI_ERR); #if INCLUDE_JVMCI if (EnableJVMCI) { @@ -4192,6 +4192,7 @@ jboolean Threads::is_supported_jni_version(jint version) { if (version == JNI_VERSION_1_6) return JNI_TRUE; if (version == JNI_VERSION_1_8) return JNI_TRUE; if (version == JNI_VERSION_9) return JNI_TRUE; + if (version == JNI_VERSION_10) return JNI_TRUE; return JNI_FALSE; } @@ -4320,17 +4321,20 @@ void Threads::assert_all_threads_claimed() { } #endif // ASSERT +class ParallelOopsDoThreadClosure : public ThreadClosure { +private: + OopClosure* _f; + CodeBlobClosure* _cf; +public: + ParallelOopsDoThreadClosure(OopClosure* f, CodeBlobClosure* cf) : _f(f), _cf(cf) {} + void do_thread(Thread* t) { + t->oops_do(_f, _cf); + } +}; + void Threads::possibly_parallel_oops_do(bool is_par, OopClosure* f, CodeBlobClosure* cf) { - int cp = Threads::thread_claim_parity(); - ALL_JAVA_THREADS(p) { - if (p->claim_oops_do(is_par, cp)) { - p->oops_do(f, cf); - } - } - VMThread* vmt = VMThread::vm_thread(); - if (vmt->claim_oops_do(is_par, cp)) { - vmt->oops_do(f, cf); - } + ParallelOopsDoThreadClosure tc(f, cf); + possibly_parallel_threads_do(is_par, &tc); } #if INCLUDE_ALL_GCS @@ -4697,13 +4701,12 @@ void Thread::SpinRelease(volatile int * adr) { // -typedef volatile intptr_t MutexT; // Mux Lock-word -enum MuxBits { LOCKBIT = 1 }; +const intptr_t LOCKBIT = 1; void Thread::muxAcquire(volatile intptr_t * Lock, const char * LockName) { - intptr_t w = Atomic::cmpxchg_ptr(LOCKBIT, Lock, 0); + intptr_t w = Atomic::cmpxchg(LOCKBIT, Lock, (intptr_t)0); if (w == 0) return; - if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) { + if ((w & LOCKBIT) == 0 && Atomic::cmpxchg(w|LOCKBIT, Lock, w) == w) { return; } @@ -4716,7 +4719,7 @@ void Thread::muxAcquire(volatile intptr_t * Lock, const char * LockName) { // Optional spin phase: spin-then-park strategy while (--its >= 0) { w = *Lock; - if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) { + if ((w & LOCKBIT) == 0 && Atomic::cmpxchg(w|LOCKBIT, Lock, w) == w) { return; } } @@ -4729,7 +4732,7 @@ void Thread::muxAcquire(volatile intptr_t * Lock, const char * LockName) { for (;;) { w = *Lock; if ((w & LOCKBIT) == 0) { - if (Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) { + if (Atomic::cmpxchg(w|LOCKBIT, Lock, w) == w) { Self->OnList = 0; // hygiene - allows stronger asserts return; } @@ -4737,7 +4740,7 @@ void Thread::muxAcquire(volatile intptr_t * Lock, const char * LockName) { } assert(w & LOCKBIT, "invariant"); Self->ListNext = (ParkEvent *) (w & ~LOCKBIT); - if (Atomic::cmpxchg_ptr(intptr_t(Self)|LOCKBIT, Lock, w) == w) break; + if (Atomic::cmpxchg(intptr_t(Self)|LOCKBIT, Lock, w) == w) break; } while (Self->OnList != 0) { @@ -4747,9 +4750,9 @@ void Thread::muxAcquire(volatile intptr_t * Lock, const char * LockName) { } void Thread::muxAcquireW(volatile intptr_t * Lock, ParkEvent * ev) { - intptr_t w = Atomic::cmpxchg_ptr(LOCKBIT, Lock, 0); + intptr_t w = Atomic::cmpxchg(LOCKBIT, Lock, (intptr_t)0); if (w == 0) return; - if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) { + if ((w & LOCKBIT) == 0 && Atomic::cmpxchg(w|LOCKBIT, Lock, w) == w) { return; } @@ -4766,7 +4769,7 @@ void Thread::muxAcquireW(volatile intptr_t * Lock, ParkEvent * ev) { // Optional spin phase: spin-then-park strategy while (--its >= 0) { w = *Lock; - if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) { + if ((w & LOCKBIT) == 0 && Atomic::cmpxchg(w|LOCKBIT, Lock, w) == w) { if (ReleaseAfter != NULL) { ParkEvent::Release(ReleaseAfter); } @@ -4782,7 +4785,7 @@ void Thread::muxAcquireW(volatile intptr_t * Lock, ParkEvent * ev) { for (;;) { w = *Lock; if ((w & LOCKBIT) == 0) { - if (Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) { + if (Atomic::cmpxchg(w|LOCKBIT, Lock, w) == w) { ev->OnList = 0; // We call ::Release while holding the outer lock, thus // artificially lengthening the critical section. @@ -4797,7 +4800,7 @@ void Thread::muxAcquireW(volatile intptr_t * Lock, ParkEvent * ev) { } assert(w & LOCKBIT, "invariant"); ev->ListNext = (ParkEvent *) (w & ~LOCKBIT); - if (Atomic::cmpxchg_ptr(intptr_t(ev)|LOCKBIT, Lock, w) == w) break; + if (Atomic::cmpxchg(intptr_t(ev)|LOCKBIT, Lock, w) == w) break; } while (ev->OnList != 0) { @@ -4833,7 +4836,7 @@ void Thread::muxAcquireW(volatile intptr_t * Lock, ParkEvent * ev) { // store (CAS) to the lock-word that releases the lock becomes globally visible. void Thread::muxRelease(volatile intptr_t * Lock) { for (;;) { - const intptr_t w = Atomic::cmpxchg_ptr(0, Lock, LOCKBIT); + const intptr_t w = Atomic::cmpxchg((intptr_t)0, Lock, LOCKBIT); assert(w & LOCKBIT, "invariant"); if (w == LOCKBIT) return; ParkEvent * const List = (ParkEvent *) (w & ~LOCKBIT); @@ -4844,7 +4847,7 @@ void Thread::muxRelease(volatile intptr_t * Lock) { // The following CAS() releases the lock and pops the head element. // The CAS() also ratifies the previously fetched lock-word value. - if (Atomic::cmpxchg_ptr (intptr_t(nxt), Lock, w) != w) { + if (Atomic::cmpxchg(intptr_t(nxt), Lock, w) != w) { continue; } List->OnList = 0; diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index bb4483589c1..feeb0cf281a 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_VM_RUNTIME_THREAD_HPP #define SHARE_VM_RUNTIME_THREAD_HPP +#include "jni.h" #include "gc/shared/threadLocalAllocBuffer.hpp" #include "memory/allocation.hpp" #include "oops/oop.hpp" -#include "prims/jni.h" #include "prims/jvmtiExport.hpp" #include "runtime/frame.hpp" #include "runtime/javaFrameAnchor.hpp" @@ -1272,7 +1272,7 @@ class JavaThread: public Thread { // we have checked is_external_suspend(), we will recheck its value // under SR_lock in java_suspend_self(). return (_special_runtime_exit_condition != _no_async_condition) || - is_external_suspend() || is_deopt_suspend() || is_trace_suspend(); + is_external_suspend() || is_trace_suspend(); } void set_pending_unsafe_access_error() { _special_runtime_exit_condition = _async_unsafe_access_error; } @@ -2052,7 +2052,7 @@ class Threads: AllStatic { static bool includes(JavaThread* p); static JavaThread* first() { return _thread_list; } static void threads_do(ThreadClosure* tc); - static void parallel_java_threads_do(ThreadClosure* tc); + static void possibly_parallel_threads_do(bool is_par, ThreadClosure* tc); // Initializes the vm and creates the vm thread static jint create_vm(JavaVMInitArgs* args, bool* canTryAgain); diff --git a/src/hotspot/share/runtime/threadCritical.hpp b/src/hotspot/share/runtime/threadCritical.hpp index 340c00fa5d1..4ae5086d773 100644 --- a/src/hotspot/share/runtime/threadCritical.hpp +++ b/src/hotspot/share/runtime/threadCritical.hpp @@ -47,11 +47,6 @@ // or CHeapObj, due to initialization issues. class ThreadCritical : public StackObj { - friend class os; - private: - static void initialize(); - static void release(); - public: ThreadCritical(); ~ThreadCritical(); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index d9dd0d15b50..30d46168d7d 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -48,6 +48,7 @@ #include "gc/parallel/mutableSpace.hpp" #include "gc/serial/defNewGeneration.hpp" #include "gc/serial/tenuredGeneration.hpp" +#include "gc/cms/cmsHeap.hpp" #include "gc/shared/cardTableRS.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/genCollectedHeap.hpp" @@ -61,6 +62,7 @@ #include "memory/allocation.inline.hpp" #include "memory/heap.hpp" #include "memory/metachunk.hpp" +#include "memory/padded.hpp" #include "memory/referenceType.hpp" #include "memory/universe.hpp" #include "memory/virtualspace.hpp" @@ -198,6 +200,8 @@ typedef HashtableEntry KlassHashtableEntry; typedef CompactHashtable SymbolCompactHashTable; typedef RehashableHashtable RehashableSymbolHashtable; +typedef PaddedEnd PaddedObjectMonitor; + //-------------------------------------------------------------------------------- // VM_STRUCTS // @@ -277,7 +281,7 @@ typedef RehashableHashtable RehashableSymbolHashtable; nonstatic_field(Klass, _secondary_super_cache, Klass*) \ nonstatic_field(Klass, _secondary_supers, Array*) \ nonstatic_field(Klass, _primary_supers[0], Klass*) \ - nonstatic_field(Klass, _java_mirror, oop) \ + nonstatic_field(Klass, _java_mirror, OopHandle) \ nonstatic_field(Klass, _modifier_flags, jint) \ nonstatic_field(Klass, _super, Klass*) \ nonstatic_field(Klass, _subklass, Klass*) \ @@ -359,7 +363,7 @@ typedef RehashableHashtable RehashableSymbolHashtable; /***********************/ \ \ volatile_nonstatic_field(ConstantPoolCacheEntry, _indices, intx) \ - nonstatic_field(ConstantPoolCacheEntry, _f1, volatile Metadata*) \ + volatile_nonstatic_field(ConstantPoolCacheEntry, _f1, Metadata*) \ volatile_nonstatic_field(ConstantPoolCacheEntry, _f2, intx) \ volatile_nonstatic_field(ConstantPoolCacheEntry, _flags, intx) \ \ @@ -1052,7 +1056,7 @@ typedef RehashableHashtable RehashableSymbolHashtable; volatile_nonstatic_field(BasicLock, _displaced_header, markOop) \ nonstatic_field(BasicObjectLock, _lock, BasicLock) \ nonstatic_field(BasicObjectLock, _obj, oop) \ - static_ptr_volatile_field(ObjectSynchronizer, gBlockList, ObjectMonitor*) \ + static_ptr_volatile_field(ObjectSynchronizer, gBlockList, PaddedObjectMonitor*) \ \ /*********************/ \ /* Matcher (C2 only) */ \ @@ -1460,6 +1464,7 @@ typedef RehashableHashtable RehashableSymbolHashtable; \ declare_toplevel_type(CollectedHeap) \ declare_type(GenCollectedHeap, CollectedHeap) \ + declare_type(CMSHeap, GenCollectedHeap) \ declare_toplevel_type(Generation) \ declare_type(DefNewGeneration, Generation) \ declare_type(CardGeneration, Generation) \ @@ -1680,6 +1685,7 @@ typedef RehashableHashtable RehashableSymbolHashtable; /************/ \ \ declare_toplevel_type(ObjectMonitor) \ + declare_toplevel_type(PaddedObjectMonitor) \ declare_toplevel_type(ObjectSynchronizer) \ declare_toplevel_type(BasicLock) \ declare_toplevel_type(BasicObjectLock) \ @@ -2154,6 +2160,7 @@ typedef RehashableHashtable RehashableSymbolHashtable; declare_toplevel_type(nmethod*) \ COMPILER2_PRESENT(declare_unsigned_integer_type(node_idx_t)) \ declare_toplevel_type(ObjectMonitor*) \ + declare_toplevel_type(PaddedObjectMonitor*) \ declare_toplevel_type(oop*) \ declare_toplevel_type(OopMap**) \ declare_toplevel_type(OopMapCache*) \ @@ -2726,8 +2733,12 @@ typedef RehashableHashtable RehashableSymbolHashtable; /* JVMCI */ \ /****************/ \ \ - declare_preprocessor_constant("INCLUDE_JVMCI", INCLUDE_JVMCI) - + declare_preprocessor_constant("INCLUDE_JVMCI", INCLUDE_JVMCI) \ + \ + /****************/ \ + /* VMRegImpl */ \ + /****************/ \ + declare_constant(VMRegImpl::stack_slot_size) //-------------------------------------------------------------------------------- // VM_LONG_CONSTANTS @@ -3009,7 +3020,8 @@ VMTypeEntry VMStructs::localHotSpotVMTypes[] = { VM_TYPES_PARNEW(GENERATE_VM_TYPE_ENTRY) VM_TYPES_G1(GENERATE_VM_TYPE_ENTRY, - GENERATE_TOPLEVEL_VM_TYPE_ENTRY) + GENERATE_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_INTEGER_VM_TYPE_ENTRY) #endif // INCLUDE_ALL_GCS #if INCLUDE_TRACE @@ -3207,6 +3219,7 @@ VMStructs::init() { VM_TYPES_PARNEW(CHECK_VM_TYPE_ENTRY) VM_TYPES_G1(CHECK_VM_TYPE_ENTRY, + CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_SINGLE_ARG_VM_TYPE_NO_OP); #endif // INCLUDE_ALL_GCS diff --git a/src/hotspot/share/runtime/vm_version.cpp b/src/hotspot/share/runtime/vm_version.cpp index b0baf79c638..c81f2f9d48b 100644 --- a/src/hotspot/share/runtime/vm_version.cpp +++ b/src/hotspot/share/runtime/vm_version.cpp @@ -95,11 +95,7 @@ bool Abstract_VM_Version::_parallel_worker_threads_initialized = false; #define VMTYPE "Server" #else // TIERED #ifdef ZERO - #ifdef SHARK - #define VMTYPE "Shark" - #else // SHARK #define VMTYPE "Zero" - #endif // SHARK #else // ZERO #define VMTYPE COMPILER1_PRESENT("Client") \ COMPILER2_PRESENT("Server") diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 18241c22448..3df6d0a8494 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -856,6 +856,29 @@ void DumperSupport::dump_static_fields(DumpWriter* writer, Klass* k) { if (fldc.access_flags().is_static()) field_count++; } + // Add in resolved_references which is referenced by the cpCache + // The resolved_references is an array per InstanceKlass holding the + // strings and other oops resolved from the constant pool. + oop resolved_references = ik->constants()->resolved_references_or_null(); + if (resolved_references != NULL) { + field_count++; + + // Add in the resolved_references of the used previous versions of the class + // in the case of RedefineClasses + InstanceKlass* prev = ik->previous_versions(); + while (prev != NULL && prev->constants()->resolved_references_or_null() != NULL) { + field_count++; + prev = prev->previous_versions(); + } + } + + // Also provide a pointer to the init_lock if present, so there aren't unreferenced int[0] + // arrays. + oop init_lock = ik->init_lock(); + if (init_lock != NULL) { + field_count++; + } + writer->write_u2(field_count); // pass 2 - dump the field descriptors and raw values @@ -873,6 +896,29 @@ void DumperSupport::dump_static_fields(DumpWriter* writer, Klass* k) { dump_field_value(writer, sig->byte_at(0), addr); } } + + // Add resolved_references for each class that has them + if (resolved_references != NULL) { + writer->write_symbolID(vmSymbols::resolved_references_name()); // name + writer->write_u1(sig2tag(vmSymbols::object_array_signature())); // type + writer->write_objectID(resolved_references); + + // Also write any previous versions + InstanceKlass* prev = ik->previous_versions(); + while (prev != NULL && prev->constants()->resolved_references_or_null() != NULL) { + writer->write_symbolID(vmSymbols::resolved_references_name()); // name + writer->write_u1(sig2tag(vmSymbols::object_array_signature())); // type + writer->write_objectID(prev->constants()->resolved_references()); + prev = prev->previous_versions(); + } + } + + // Add init lock to the end if the class is not yet initialized + if (init_lock != NULL) { + writer->write_symbolID(vmSymbols::init_lock_name()); // name + writer->write_u1(sig2tag(vmSymbols::int_array_signature())); // type + writer->write_objectID(init_lock); + } } // dump the raw values of the instance fields of the given object @@ -908,7 +954,7 @@ void DumperSupport::dump_instance_field_descriptors(DumpWriter* writer, Klass* k if (!fld.access_flags().is_static()) { Symbol* sig = fld.signature(); - writer->write_symbolID(fld.name()); // name + writer->write_symbolID(fld.name()); // name writer->write_u1(sig2tag(sig)); // type } } @@ -1822,6 +1868,8 @@ void VM_HeapDumper::doit() { // HPROF_GC_ROOT_JNI_GLOBAL JNIGlobalsDumper jni_dumper(writer()); JNIHandles::oops_do(&jni_dumper); + Universe::oops_do(&jni_dumper); // technically not jni roots, but global roots + // for things like preallocated throwable backtraces check_segment_length(); // HPROF_GC_ROOT_STICKY_CLASS diff --git a/src/hotspot/share/services/jmm.h b/src/hotspot/share/services/jmm.h index b6497cd8982..df232f6feec 100644 --- a/src/hotspot/share/services/jmm.h +++ b/src/hotspot/share/services/jmm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -50,7 +50,8 @@ enum { JMM_VERSION_1_2 = 0x20010200, // JDK 7 JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA JMM_VERSION_1_2_2 = 0x20010202, - JMM_VERSION = 0x20010203 + JMM_VERSION_2 = 0x20020000, // JDK 10 + JMM_VERSION = 0x20020000 }; typedef struct { @@ -315,7 +316,8 @@ typedef struct jmmInterface_1_ { jobjectArray (JNICALL *DumpThreads) (JNIEnv *env, jlongArray ids, jboolean lockedMonitors, - jboolean lockedSynchronizers); + jboolean lockedSynchronizers, + jint maxDepth); void (JNICALL *SetGCNotificationEnabled) (JNIEnv *env, jobject mgr, jboolean enabled); diff --git a/src/hotspot/share/services/mallocSiteTable.cpp b/src/hotspot/share/services/mallocSiteTable.cpp index 1893f0bb155..472b461f491 100644 --- a/src/hotspot/share/services/mallocSiteTable.cpp +++ b/src/hotspot/share/services/mallocSiteTable.cpp @@ -147,7 +147,7 @@ MallocSite* MallocSiteTable::lookup_or_add(const NativeCallStack& key, size_t* b if (entry == NULL) return NULL; // swap in the head - if (Atomic::cmpxchg_ptr((void*)entry, (volatile void *)&_table[index], NULL) == NULL) { + if (Atomic::cmpxchg(entry, &_table[index], (MallocSiteHashtableEntry*)NULL) == NULL) { return entry->data(); } @@ -257,3 +257,7 @@ void MallocSiteTable::AccessLock::exclusiveLock() { } _lock_state = ExclusiveLock; } + +bool MallocSiteHashtableEntry::atomic_insert(MallocSiteHashtableEntry* entry) { + return Atomic::cmpxchg(entry, &_next, (MallocSiteHashtableEntry*)NULL) == NULL; +} diff --git a/src/hotspot/share/services/mallocSiteTable.hpp b/src/hotspot/share/services/mallocSiteTable.hpp index fa4d2b54801..b5c1e235127 100644 --- a/src/hotspot/share/services/mallocSiteTable.hpp +++ b/src/hotspot/share/services/mallocSiteTable.hpp @@ -61,8 +61,8 @@ class MallocSite : public AllocationSite { // Malloc site hashtable entry class MallocSiteHashtableEntry : public CHeapObj { private: - MallocSite _malloc_site; - MallocSiteHashtableEntry* _next; + MallocSite _malloc_site; + MallocSiteHashtableEntry* volatile _next; public: MallocSiteHashtableEntry() : _next(NULL) { } @@ -79,10 +79,7 @@ class MallocSiteHashtableEntry : public CHeapObj { // Insert an entry atomically. // Return true if the entry is inserted successfully. // The operation can be failed due to contention from other thread. - bool atomic_insert(const MallocSiteHashtableEntry* entry) { - return (Atomic::cmpxchg_ptr((void*)entry, (volatile void*)&_next, - NULL) == NULL); - } + bool atomic_insert(MallocSiteHashtableEntry* entry); void set_callsite(const MallocSite& site) { _malloc_site = site; diff --git a/src/hotspot/share/services/mallocTracker.hpp b/src/hotspot/share/services/mallocTracker.hpp index d77ddd0ad75..46063a84491 100644 --- a/src/hotspot/share/services/mallocTracker.hpp +++ b/src/hotspot/share/services/mallocTracker.hpp @@ -68,7 +68,7 @@ class MemoryCounter VALUE_OBJ_CLASS_SPEC { if (sz > 0) { // unary minus operator applied to unsigned type, result still unsigned #pragma warning(suppress: 4146) - Atomic::add(-sz, &_size); + Atomic::sub(sz, &_size); } } diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index 12d88b7419f..bc50816d83d 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -1160,7 +1160,8 @@ JVM_END // locked_monitors - if true, dump locked object monitors // locked_synchronizers - if true, dump locked JSR-166 synchronizers // -JVM_ENTRY(jobjectArray, jmm_DumpThreads(JNIEnv *env, jlongArray thread_ids, jboolean locked_monitors, jboolean locked_synchronizers)) +JVM_ENTRY(jobjectArray, jmm_DumpThreads(JNIEnv *env, jlongArray thread_ids, jboolean locked_monitors, + jboolean locked_synchronizers, jint maxDepth)) ResourceMark rm(THREAD); // make sure the AbstractOwnableSynchronizer klass is loaded before taking thread snapshots @@ -1181,14 +1182,14 @@ JVM_ENTRY(jobjectArray, jmm_DumpThreads(JNIEnv *env, jlongArray thread_ids, jboo do_thread_dump(&dump_result, ids_ah, num_threads, - -1, /* entire stack */ + maxDepth, /* stack depth */ (locked_monitors ? true : false), /* with locked monitors */ (locked_synchronizers ? true : false), /* with locked synchronizers */ CHECK_NULL); } else { // obtain thread dump of all threads VM_ThreadDump op(&dump_result, - -1, /* entire stack */ + maxDepth, /* stack depth */ (locked_monitors ? true : false), /* with locked monitors */ (locked_synchronizers ? true : false) /* with locked synchronizers */); VMThread::execute(&op); @@ -2237,7 +2238,7 @@ const struct jmmInterface_1_ jmm_interface = { void* Management::get_jmm_interface(int version) { #if INCLUDE_MANAGEMENT - if (version == JMM_VERSION_1_0) { + if (version == JMM_VERSION) { return (void*) &jmm_interface; } #endif // INCLUDE_MANAGEMENT diff --git a/src/hotspot/share/services/memBaseline.cpp b/src/hotspot/share/services/memBaseline.cpp index f580aada254..f2d6c36188c 100644 --- a/src/hotspot/share/services/memBaseline.cpp +++ b/src/hotspot/share/services/memBaseline.cpp @@ -144,6 +144,7 @@ class VirtualMemoryAllocationWalker : public VirtualMemoryWalker { bool MemBaseline::baseline_summary() { MallocMemorySummary::snapshot(&_malloc_memory_snapshot); VirtualMemorySummary::snapshot(&_virtual_memory_snapshot); + MetaspaceSnapshot::snapshot(_metaspace_snapshot); return true; } diff --git a/src/hotspot/share/services/memBaseline.hpp b/src/hotspot/share/services/memBaseline.hpp index 238d29d82fe..9040306aca4 100644 --- a/src/hotspot/share/services/memBaseline.hpp +++ b/src/hotspot/share/services/memBaseline.hpp @@ -65,6 +65,7 @@ class MemBaseline VALUE_OBJ_CLASS_SPEC { // Summary information MallocMemorySnapshot _malloc_memory_snapshot; VirtualMemorySnapshot _virtual_memory_snapshot; + MetaspaceSnapshot _metaspace_snapshot; size_t _class_count; @@ -103,6 +104,10 @@ class MemBaseline VALUE_OBJ_CLASS_SPEC { return &_virtual_memory_snapshot; } + MetaspaceSnapshot* metaspace_snapshot() { + return &_metaspace_snapshot; + } + MallocSiteIterator malloc_sites(SortingOrder order); VirtualMemorySiteIterator virtual_memory_sites(SortingOrder order); diff --git a/src/hotspot/share/services/memReporter.cpp b/src/hotspot/share/services/memReporter.cpp index 8199ee0aa68..77abb49833d 100644 --- a/src/hotspot/share/services/memReporter.cpp +++ b/src/hotspot/share/services/memReporter.cpp @@ -175,12 +175,44 @@ void MemSummaryReporter::report_summary_of_type(MEMFLAGS flag, amount_in_current_scale(_malloc_snapshot->malloc_overhead()->size()) > 0) { out->print_cr("%27s (tracking overhead=" SIZE_FORMAT "%s)", " ", amount_in_current_scale(_malloc_snapshot->malloc_overhead()->size()), scale); + } else if (flag == mtClass) { + // Metadata information + report_metadata(Metaspace::NonClassType); + if (Metaspace::using_class_space()) { + report_metadata(Metaspace::ClassType); + } } - out->print_cr(" "); } } +void MemSummaryReporter::report_metadata(Metaspace::MetadataType type) const { + assert(type == Metaspace::NonClassType || type == Metaspace::ClassType, + "Invalid metadata type"); + const char* name = (type == Metaspace::NonClassType) ? + "Metadata: " : "Class space:"; + + outputStream* out = output(); + const char* scale = current_scale(); + size_t committed = MetaspaceAux::committed_bytes(type); + size_t used = MetaspaceAux::used_bytes(type); + size_t free = (MetaspaceAux::capacity_bytes(type) - used) + + MetaspaceAux::free_chunks_total_bytes(type) + + MetaspaceAux::free_bytes(type); + + assert(committed >= used + free, "Sanity"); + size_t waste = committed - (used + free); + + out->print_cr("%27s ( %s)", " ", name); + out->print("%27s ( ", " "); + print_total(MetaspaceAux::reserved_bytes(type), committed); + out->print_cr(")"); + out->print_cr("%27s ( used=" SIZE_FORMAT "%s)", " ", amount_in_current_scale(used), scale); + out->print_cr("%27s ( free=" SIZE_FORMAT "%s)", " ", amount_in_current_scale(free), scale); + out->print_cr("%27s ( waste=" SIZE_FORMAT "%s =%2.2f%%)", " ", amount_in_current_scale(waste), + scale, ((float)waste * 100)/committed); +} + void MemDetailReporter::report_detail() { // Start detail report outputStream* out = output(); @@ -305,9 +337,13 @@ void MemSummaryDiffReporter::report_diff() { MEMFLAGS flag = NMTUtil::index_to_flag(index); // thread stack is reported as part of thread category if (flag == mtThreadStack) continue; - diff_summary_of_type(flag, _early_baseline.malloc_memory(flag), - _early_baseline.virtual_memory(flag), _current_baseline.malloc_memory(flag), - _current_baseline.virtual_memory(flag)); + diff_summary_of_type(flag, + _early_baseline.malloc_memory(flag), + _early_baseline.virtual_memory(flag), + _early_baseline.metaspace_snapshot(), + _current_baseline.malloc_memory(flag), + _current_baseline.virtual_memory(flag), + _current_baseline.metaspace_snapshot()); } } @@ -367,9 +403,11 @@ void MemSummaryDiffReporter::print_virtual_memory_diff(size_t current_reserved, } -void MemSummaryDiffReporter::diff_summary_of_type(MEMFLAGS flag, const MallocMemory* early_malloc, - const VirtualMemory* early_vm, const MallocMemory* current_malloc, - const VirtualMemory* current_vm) const { +void MemSummaryDiffReporter::diff_summary_of_type(MEMFLAGS flag, + const MallocMemory* early_malloc, const VirtualMemory* early_vm, + const MetaspaceSnapshot* early_ms, + const MallocMemory* current_malloc, const VirtualMemory* current_vm, + const MetaspaceSnapshot* current_ms) const { outputStream* out = output(); const char* scale = current_scale(); @@ -486,11 +524,77 @@ void MemSummaryDiffReporter::diff_summary_of_type(MEMFLAGS flag, const MallocMem out->print(" %+ld%s", overhead_diff, scale); } out->print_cr(")"); + } else if (flag == mtClass) { + assert(current_ms != NULL && early_ms != NULL, "Sanity"); + print_metaspace_diff(current_ms, early_ms); } out->print_cr(" "); } } +void MemSummaryDiffReporter::print_metaspace_diff(const MetaspaceSnapshot* current_ms, + const MetaspaceSnapshot* early_ms) const { + print_metaspace_diff(Metaspace::NonClassType, current_ms, early_ms); + if (Metaspace::using_class_space()) { + print_metaspace_diff(Metaspace::ClassType, current_ms, early_ms); + } +} + +void MemSummaryDiffReporter::print_metaspace_diff(Metaspace::MetadataType type, + const MetaspaceSnapshot* current_ms, + const MetaspaceSnapshot* early_ms) const { + const char* name = (type == Metaspace::NonClassType) ? + "Metadata: " : "Class space:"; + + outputStream* out = output(); + const char* scale = current_scale(); + + out->print_cr("%27s ( %s)", " ", name); + out->print("%27s ( ", " "); + print_virtual_memory_diff(current_ms->reserved_in_bytes(type), + current_ms->committed_in_bytes(type), + early_ms->reserved_in_bytes(type), + early_ms->committed_in_bytes(type)); + out->print_cr(")"); + + long diff_used = diff_in_current_scale(current_ms->used_in_bytes(type), + early_ms->used_in_bytes(type)); + long diff_free = diff_in_current_scale(current_ms->free_in_bytes(type), + early_ms->free_in_bytes(type)); + + size_t current_waste = current_ms->committed_in_bytes(type) + - (current_ms->used_in_bytes(type) + current_ms->free_in_bytes(type)); + size_t early_waste = early_ms->committed_in_bytes(type) + - (early_ms->used_in_bytes(type) + early_ms->free_in_bytes(type)); + long diff_waste = diff_in_current_scale(current_waste, early_waste); + + // Diff used + out->print("%27s ( used=" SIZE_FORMAT "%s", " ", + amount_in_current_scale(current_ms->used_in_bytes(type)), scale); + if (diff_used != 0) { + out->print(" %+ld%s", diff_used, scale); + } + out->print_cr(")"); + + // Diff free + out->print("%27s ( free=" SIZE_FORMAT "%s", " ", + amount_in_current_scale(current_ms->free_in_bytes(type)), scale); + if (diff_free != 0) { + out->print(" %+ld%s", diff_free, scale); + } + out->print_cr(")"); + + + // Diff waste + out->print("%27s ( waste=" SIZE_FORMAT "%s =%2.2f%%", " ", + amount_in_current_scale(current_waste), scale, + ((float)current_waste * 100) / current_ms->committed_in_bytes(type)); + if (diff_waste != 0) { + out->print(" %+ld%s", diff_waste, scale); + } + out->print_cr(")"); +} + void MemDetailDiffReporter::report_diff() { MemSummaryDiffReporter::report_diff(); diff_malloc_sites(); diff --git a/src/hotspot/share/services/memReporter.hpp b/src/hotspot/share/services/memReporter.hpp index 9b83f8ce4f0..f244ad55248 100644 --- a/src/hotspot/share/services/memReporter.hpp +++ b/src/hotspot/share/services/memReporter.hpp @@ -27,6 +27,7 @@ #if INCLUDE_NMT +#include "memory/metaspace.hpp" #include "oops/instanceKlass.hpp" #include "services/memBaseline.hpp" #include "services/nmtCommon.hpp" @@ -110,6 +111,8 @@ class MemSummaryReporter : public MemReporterBase { // Report summary for each memory type void report_summary_of_type(MEMFLAGS type, MallocMemory* malloc_memory, VirtualMemory* virtual_memory); + + void report_metadata(Metaspace::MetadataType type) const; }; /* @@ -170,7 +173,9 @@ class MemSummaryDiffReporter : public MemReporterBase { // report the comparison of each memory type void diff_summary_of_type(MEMFLAGS type, const MallocMemory* early_malloc, const VirtualMemory* early_vm, - const MallocMemory* current_malloc, const VirtualMemory* current_vm) const; + const MetaspaceSnapshot* early_ms, + const MallocMemory* current_malloc, const VirtualMemory* current_vm, + const MetaspaceSnapshot* current_ms) const; protected: void print_malloc_diff(size_t current_amount, size_t current_count, @@ -179,6 +184,11 @@ class MemSummaryDiffReporter : public MemReporterBase { size_t early_reserved, size_t early_committed) const; void print_arena_diff(size_t current_amount, size_t current_count, size_t early_amount, size_t early_count) const; + + void print_metaspace_diff(const MetaspaceSnapshot* current_ms, + const MetaspaceSnapshot* early_ms) const; + void print_metaspace_diff(Metaspace::MetadataType type, + const MetaspaceSnapshot* current_ms, const MetaspaceSnapshot* early_ms) const; }; /* diff --git a/src/hotspot/share/services/memoryManager.cpp b/src/hotspot/share/services/memoryManager.cpp index 8443f437034..8c6fc6d6f1a 100644 --- a/src/hotspot/share/services/memoryManager.cpp +++ b/src/hotspot/share/services/memoryManager.cpp @@ -94,7 +94,7 @@ GCMemoryManager* MemoryManager::get_g1OldGen_memory_manager() { instanceOop MemoryManager::get_memory_manager_instance(TRAPS) { // Must do an acquire so as to force ordering of subsequent // loads from anything _memory_mgr_obj points to or implies. - instanceOop mgr_obj = (instanceOop)OrderAccess::load_ptr_acquire(&_memory_mgr_obj); + instanceOop mgr_obj = OrderAccess::load_acquire(&_memory_mgr_obj); if (mgr_obj == NULL) { // It's ok for more than one thread to execute the code up to the locked region. // Extra manager instances will just be gc'ed. @@ -147,7 +147,7 @@ instanceOop MemoryManager::get_memory_manager_instance(TRAPS) { // // The lock has done an acquire, so the load can't float above it, but // we need to do a load_acquire as above. - mgr_obj = (instanceOop)OrderAccess::load_ptr_acquire(&_memory_mgr_obj); + mgr_obj = OrderAccess::load_acquire(&_memory_mgr_obj); if (mgr_obj != NULL) { return mgr_obj; } @@ -159,7 +159,7 @@ instanceOop MemoryManager::get_memory_manager_instance(TRAPS) { // with creating the management object are visible before publishing // its address. The unlock will publish the store to _memory_mgr_obj // because it does a release first. - OrderAccess::release_store_ptr(&_memory_mgr_obj, mgr_obj); + OrderAccess::release_store(&_memory_mgr_obj, mgr_obj); } } diff --git a/src/hotspot/share/services/memoryPool.cpp b/src/hotspot/share/services/memoryPool.cpp index a29a27310cf..cec78ae67a4 100644 --- a/src/hotspot/share/services/memoryPool.cpp +++ b/src/hotspot/share/services/memoryPool.cpp @@ -82,7 +82,7 @@ void MemoryPool::add_manager(MemoryManager* mgr) { instanceOop MemoryPool::get_memory_pool_instance(TRAPS) { // Must do an acquire so as to force ordering of subsequent // loads from anything _memory_pool_obj points to or implies. - instanceOop pool_obj = (instanceOop)OrderAccess::load_ptr_acquire(&_memory_pool_obj); + instanceOop pool_obj = OrderAccess::load_acquire(&_memory_pool_obj); if (pool_obj == NULL) { // It's ok for more than one thread to execute the code up to the locked region. // Extra pool instances will just be gc'ed. @@ -123,7 +123,7 @@ instanceOop MemoryPool::get_memory_pool_instance(TRAPS) { // // The lock has done an acquire, so the load can't float above it, // but we need to do a load_acquire as above. - pool_obj = (instanceOop)OrderAccess::load_ptr_acquire(&_memory_pool_obj); + pool_obj = OrderAccess::load_acquire(&_memory_pool_obj); if (pool_obj != NULL) { return pool_obj; } @@ -135,7 +135,7 @@ instanceOop MemoryPool::get_memory_pool_instance(TRAPS) { // with creating the pool are visible before publishing its address. // The unlock will publish the store to _memory_pool_obj because // it does a release first. - OrderAccess::release_store_ptr(&_memory_pool_obj, pool_obj); + OrderAccess::release_store(&_memory_pool_obj, pool_obj); } } diff --git a/src/hotspot/share/services/memoryService.cpp b/src/hotspot/share/services/memoryService.cpp index aed39e9451b..31a32b4bdd6 100644 --- a/src/hotspot/share/services/memoryService.cpp +++ b/src/hotspot/share/services/memoryService.cpp @@ -86,7 +86,8 @@ void GcThreadCountClosure::do_thread(Thread* thread) { void MemoryService::set_universe_heap(CollectedHeap* heap) { CollectedHeap::Name kind = heap->kind(); switch (kind) { - case CollectedHeap::GenCollectedHeap : { + case CollectedHeap::GenCollectedHeap : + case CollectedHeap::CMSHeap : { add_gen_collected_heap_info(GenCollectedHeap::heap()); break; } diff --git a/src/hotspot/share/services/threadService.cpp b/src/hotspot/share/services/threadService.cpp index 1100cb07971..da25120bb37 100644 --- a/src/hotspot/share/services/threadService.cpp +++ b/src/hotspot/share/services/threadService.cpp @@ -562,6 +562,10 @@ void ThreadStackTrace::dump_stack_at_safepoint(int maxDepth) { vframe* start_vf = _thread->last_java_vframe(®_map); int count = 0; for (vframe* f = start_vf; f; f = f->sender() ) { + if (maxDepth >= 0 && count == maxDepth) { + // Skip frames if more than maxDepth + break; + } if (f->is_java_frame()) { javaVFrame* jvf = javaVFrame::cast(f); add_stack_frame(jvf); @@ -569,10 +573,6 @@ void ThreadStackTrace::dump_stack_at_safepoint(int maxDepth) { } else { // Ignore non-Java frames } - if (maxDepth > 0 && count == maxDepth) { - // Skip frames if more than maxDepth - break; - } } } diff --git a/src/hotspot/share/services/virtualMemoryTracker.cpp b/src/hotspot/share/services/virtualMemoryTracker.cpp index c21aa542b2d..97bc9d5ef7c 100644 --- a/src/hotspot/share/services/virtualMemoryTracker.cpp +++ b/src/hotspot/share/services/virtualMemoryTracker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, 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,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/metaspace.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "runtime/threadCritical.hpp" @@ -492,3 +493,35 @@ bool VirtualMemoryTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel return true; } + +// Metaspace Support +MetaspaceSnapshot::MetaspaceSnapshot() { + for (int index = (int)Metaspace::ClassType; index < (int)Metaspace::MetadataTypeCount; index ++) { + Metaspace::MetadataType type = (Metaspace::MetadataType)index; + assert_valid_metadata_type(type); + _reserved_in_bytes[type] = 0; + _committed_in_bytes[type] = 0; + _used_in_bytes[type] = 0; + _free_in_bytes[type] = 0; + } +} + +void MetaspaceSnapshot::snapshot(Metaspace::MetadataType type, MetaspaceSnapshot& mss) { + assert_valid_metadata_type(type); + + mss._reserved_in_bytes[type] = MetaspaceAux::reserved_bytes(type); + mss._committed_in_bytes[type] = MetaspaceAux::committed_bytes(type); + mss._used_in_bytes[type] = MetaspaceAux::used_bytes(type); + + size_t free_in_bytes = (MetaspaceAux::capacity_bytes(type) - MetaspaceAux::used_bytes(type)) + + MetaspaceAux::free_chunks_total_bytes(type) + + MetaspaceAux::free_bytes(type); + mss._free_in_bytes[type] = free_in_bytes; +} + +void MetaspaceSnapshot::snapshot(MetaspaceSnapshot& mss) { + snapshot(Metaspace::ClassType, mss); + if (Metaspace::using_class_space()) { + snapshot(Metaspace::NonClassType, mss); + } +} diff --git a/src/hotspot/share/services/virtualMemoryTracker.hpp b/src/hotspot/share/services/virtualMemoryTracker.hpp index 02d21bd53bb..9a02676ade0 100644 --- a/src/hotspot/share/services/virtualMemoryTracker.hpp +++ b/src/hotspot/share/services/virtualMemoryTracker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, 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 @@ -28,6 +28,7 @@ #if INCLUDE_NMT #include "memory/allocation.hpp" +#include "memory/metaspace.hpp" #include "services/allocationSite.hpp" #include "services/nmtCommon.hpp" #include "utilities/linkedlist.hpp" @@ -419,6 +420,31 @@ class VirtualMemoryTracker : AllStatic { }; +class MetaspaceSnapshot : public ResourceObj { +private: + size_t _reserved_in_bytes[Metaspace::MetadataTypeCount]; + size_t _committed_in_bytes[Metaspace::MetadataTypeCount]; + size_t _used_in_bytes[Metaspace::MetadataTypeCount]; + size_t _free_in_bytes[Metaspace::MetadataTypeCount]; + +public: + MetaspaceSnapshot(); + size_t reserved_in_bytes(Metaspace::MetadataType type) const { assert_valid_metadata_type(type); return _reserved_in_bytes[type]; } + size_t committed_in_bytes(Metaspace::MetadataType type) const { assert_valid_metadata_type(type); return _committed_in_bytes[type]; } + size_t used_in_bytes(Metaspace::MetadataType type) const { assert_valid_metadata_type(type); return _used_in_bytes[type]; } + size_t free_in_bytes(Metaspace::MetadataType type) const { assert_valid_metadata_type(type); return _free_in_bytes[type]; } + + static void snapshot(MetaspaceSnapshot& s); + +private: + static void snapshot(Metaspace::MetadataType type, MetaspaceSnapshot& s); + + static void assert_valid_metadata_type(Metaspace::MetadataType type) { + assert(type == Metaspace::ClassType || type == Metaspace::NonClassType, + "Invalid metadata type"); + } +}; + #endif // INCLUDE_NMT #endif // SHARE_VM_SERVICES_VIRTUAL_MEMORY_TRACKER_HPP diff --git a/src/hotspot/share/shark/llvmHeaders.hpp b/src/hotspot/share/shark/llvmHeaders.hpp deleted file mode 100644 index b4bd45b8f52..00000000000 --- a/src/hotspot/share/shark/llvmHeaders.hpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_LLVMHEADERS_HPP -#define SHARE_VM_SHARK_LLVMHEADERS_HPP - -#ifdef assert - #undef assert -#endif - -#ifdef DEBUG - #define SHARK_DEBUG - #undef DEBUG -#endif - -#include -#include - -// includes specific to each version -#if SHARK_LLVM_VERSION <= 31 -#include -#include -#include -#include -#include -#include -#include -#include -#elif SHARK_LLVM_VERSION <= 32 -#include -#include -#include -#include -#include -#include -#include -#include -#else // SHARK_LLVM_VERSION <= 34 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -// common includes -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef assert - #undef assert -#endif - -#define assert(p, msg) vmassert(p, msg) - -#ifdef DEBUG - #undef DEBUG -#endif -#ifdef SHARK_DEBUG - #define DEBUG - #undef SHARK_DEBUG -#endif - -#endif // SHARE_VM_SHARK_LLVMHEADERS_HPP diff --git a/src/hotspot/share/shark/llvmValue.hpp b/src/hotspot/share/shark/llvmValue.hpp deleted file mode 100644 index 4eef6ef8142..00000000000 --- a/src/hotspot/share/shark/llvmValue.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_LLVMVALUE_HPP -#define SHARE_VM_SHARK_LLVMVALUE_HPP - -#include "shark/llvmHeaders.hpp" -#include "shark/sharkContext.hpp" -#include "shark/sharkType.hpp" - -class LLVMValue : public AllStatic { - public: - static llvm::ConstantInt* jbyte_constant(jbyte value) - { - return llvm::ConstantInt::get(SharkType::jbyte_type(), value, true); - } - static llvm::ConstantInt* jint_constant(jint value) - { - return llvm::ConstantInt::get(SharkType::jint_type(), value, true); - } - static llvm::ConstantInt* jlong_constant(jlong value) - { - return llvm::ConstantInt::get(SharkType::jlong_type(), value, true); - } - static llvm::ConstantFP* jfloat_constant(jfloat value) - { - return llvm::ConstantFP::get(SharkContext::current(), llvm::APFloat(value)); - } - static llvm::ConstantFP* jdouble_constant(jdouble value) - { - return llvm::ConstantFP::get(SharkContext::current(), llvm::APFloat(value)); - } - static llvm::ConstantPointerNull* null() - { - return llvm::ConstantPointerNull::get(SharkType::oop_type()); - } - static llvm::ConstantPointerNull* nullKlass() - { - return llvm::ConstantPointerNull::get(SharkType::klass_type()); - } - - public: - static llvm::ConstantInt* bit_constant(int value) - { - return llvm::ConstantInt::get(SharkType::bit_type(), value, false); - } - static llvm::ConstantInt* intptr_constant(intptr_t value) - { - return llvm::ConstantInt::get(SharkType::intptr_type(), value, false); - } -}; - -#endif // SHARE_VM_SHARK_LLVMVALUE_HPP diff --git a/src/hotspot/share/shark/sharkBlock.cpp b/src/hotspot/share/shark/sharkBlock.cpp deleted file mode 100644 index faa6694c9fd..00000000000 --- a/src/hotspot/share/shark/sharkBlock.cpp +++ /dev/null @@ -1,1286 +0,0 @@ -/* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "interpreter/bytecodes.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/llvmValue.hpp" -#include "shark/sharkBlock.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkConstant.hpp" -#include "shark/sharkState.hpp" -#include "shark/sharkValue.hpp" -#include "shark/shark_globals.hpp" -#include "utilities/debug.hpp" - -using namespace llvm; - -void SharkBlock::parse_bytecode(int start, int limit) { - SharkValue *a, *b, *c, *d; - int i; - - // Ensure the current state is initialized before we emit any code, - // so that any setup code for the state is at the start of the block - current_state(); - - // Parse the bytecodes - iter()->reset_to_bci(start); - while (iter()->next_bci() < limit) { - NOT_PRODUCT(a = b = c = d = NULL); - iter()->next(); - - if (SharkTraceBytecodes) - tty->print_cr("%4d: %s", bci(), Bytecodes::name(bc())); - - if (has_trap() && trap_bci() == bci()) { - do_trap(trap_request()); - return; - } - - if (UseLoopSafepoints) { - // XXX if a lcmp is followed by an if_?? then C2 maybe-inserts - // the safepoint before the lcmp rather than before the if. - // Maybe we should do this too. See parse2.cpp for details. - switch (bc()) { - case Bytecodes::_goto: - case Bytecodes::_ifnull: - case Bytecodes::_ifnonnull: - case Bytecodes::_if_acmpeq: - case Bytecodes::_if_acmpne: - case Bytecodes::_ifeq: - case Bytecodes::_ifne: - case Bytecodes::_iflt: - case Bytecodes::_ifle: - case Bytecodes::_ifgt: - case Bytecodes::_ifge: - case Bytecodes::_if_icmpeq: - case Bytecodes::_if_icmpne: - case Bytecodes::_if_icmplt: - case Bytecodes::_if_icmple: - case Bytecodes::_if_icmpgt: - case Bytecodes::_if_icmpge: - if (iter()->get_dest() <= bci()) - maybe_add_backedge_safepoint(); - break; - - case Bytecodes::_goto_w: - if (iter()->get_far_dest() <= bci()) - maybe_add_backedge_safepoint(); - break; - - case Bytecodes::_tableswitch: - case Bytecodes::_lookupswitch: - if (switch_default_dest() <= bci()) { - maybe_add_backedge_safepoint(); - break; - } - int len = switch_table_length(); - for (int i = 0; i < len; i++) { - if (switch_dest(i) <= bci()) { - maybe_add_backedge_safepoint(); - break; - } - } - break; - } - } - - switch (bc()) { - case Bytecodes::_nop: - break; - - case Bytecodes::_aconst_null: - push(SharkValue::null()); - break; - - case Bytecodes::_iconst_m1: - push(SharkValue::jint_constant(-1)); - break; - case Bytecodes::_iconst_0: - push(SharkValue::jint_constant(0)); - break; - case Bytecodes::_iconst_1: - push(SharkValue::jint_constant(1)); - break; - case Bytecodes::_iconst_2: - push(SharkValue::jint_constant(2)); - break; - case Bytecodes::_iconst_3: - push(SharkValue::jint_constant(3)); - break; - case Bytecodes::_iconst_4: - push(SharkValue::jint_constant(4)); - break; - case Bytecodes::_iconst_5: - push(SharkValue::jint_constant(5)); - break; - - case Bytecodes::_lconst_0: - push(SharkValue::jlong_constant(0)); - break; - case Bytecodes::_lconst_1: - push(SharkValue::jlong_constant(1)); - break; - - case Bytecodes::_fconst_0: - push(SharkValue::jfloat_constant(0)); - break; - case Bytecodes::_fconst_1: - push(SharkValue::jfloat_constant(1)); - break; - case Bytecodes::_fconst_2: - push(SharkValue::jfloat_constant(2)); - break; - - case Bytecodes::_dconst_0: - push(SharkValue::jdouble_constant(0)); - break; - case Bytecodes::_dconst_1: - push(SharkValue::jdouble_constant(1)); - break; - - case Bytecodes::_bipush: - push(SharkValue::jint_constant(iter()->get_constant_u1())); - break; - case Bytecodes::_sipush: - push(SharkValue::jint_constant(iter()->get_constant_u2())); - break; - - case Bytecodes::_ldc: - case Bytecodes::_ldc_w: - case Bytecodes::_ldc2_w: { - SharkConstant* constant = SharkConstant::for_ldc(iter()); - assert(constant->is_loaded(), "trap should handle unloaded classes"); - push(constant->value(builder())); - break; - } - case Bytecodes::_iload_0: - case Bytecodes::_lload_0: - case Bytecodes::_fload_0: - case Bytecodes::_dload_0: - case Bytecodes::_aload_0: - push(local(0)); - break; - case Bytecodes::_iload_1: - case Bytecodes::_lload_1: - case Bytecodes::_fload_1: - case Bytecodes::_dload_1: - case Bytecodes::_aload_1: - push(local(1)); - break; - case Bytecodes::_iload_2: - case Bytecodes::_lload_2: - case Bytecodes::_fload_2: - case Bytecodes::_dload_2: - case Bytecodes::_aload_2: - push(local(2)); - break; - case Bytecodes::_iload_3: - case Bytecodes::_lload_3: - case Bytecodes::_fload_3: - case Bytecodes::_dload_3: - case Bytecodes::_aload_3: - push(local(3)); - break; - case Bytecodes::_iload: - case Bytecodes::_lload: - case Bytecodes::_fload: - case Bytecodes::_dload: - case Bytecodes::_aload: - push(local(iter()->get_index())); - break; - - case Bytecodes::_baload: - do_aload(T_BYTE); - break; - case Bytecodes::_caload: - do_aload(T_CHAR); - break; - case Bytecodes::_saload: - do_aload(T_SHORT); - break; - case Bytecodes::_iaload: - do_aload(T_INT); - break; - case Bytecodes::_laload: - do_aload(T_LONG); - break; - case Bytecodes::_faload: - do_aload(T_FLOAT); - break; - case Bytecodes::_daload: - do_aload(T_DOUBLE); - break; - case Bytecodes::_aaload: - do_aload(T_OBJECT); - break; - - case Bytecodes::_istore_0: - case Bytecodes::_lstore_0: - case Bytecodes::_fstore_0: - case Bytecodes::_dstore_0: - case Bytecodes::_astore_0: - set_local(0, pop()); - break; - case Bytecodes::_istore_1: - case Bytecodes::_lstore_1: - case Bytecodes::_fstore_1: - case Bytecodes::_dstore_1: - case Bytecodes::_astore_1: - set_local(1, pop()); - break; - case Bytecodes::_istore_2: - case Bytecodes::_lstore_2: - case Bytecodes::_fstore_2: - case Bytecodes::_dstore_2: - case Bytecodes::_astore_2: - set_local(2, pop()); - break; - case Bytecodes::_istore_3: - case Bytecodes::_lstore_3: - case Bytecodes::_fstore_3: - case Bytecodes::_dstore_3: - case Bytecodes::_astore_3: - set_local(3, pop()); - break; - case Bytecodes::_istore: - case Bytecodes::_lstore: - case Bytecodes::_fstore: - case Bytecodes::_dstore: - case Bytecodes::_astore: - set_local(iter()->get_index(), pop()); - break; - - case Bytecodes::_bastore: - do_astore(T_BYTE); - break; - case Bytecodes::_castore: - do_astore(T_CHAR); - break; - case Bytecodes::_sastore: - do_astore(T_SHORT); - break; - case Bytecodes::_iastore: - do_astore(T_INT); - break; - case Bytecodes::_lastore: - do_astore(T_LONG); - break; - case Bytecodes::_fastore: - do_astore(T_FLOAT); - break; - case Bytecodes::_dastore: - do_astore(T_DOUBLE); - break; - case Bytecodes::_aastore: - do_astore(T_OBJECT); - break; - - case Bytecodes::_pop: - xpop(); - break; - case Bytecodes::_pop2: - xpop(); - xpop(); - break; - case Bytecodes::_swap: - a = xpop(); - b = xpop(); - xpush(a); - xpush(b); - break; - case Bytecodes::_dup: - a = xpop(); - xpush(a); - xpush(a); - break; - case Bytecodes::_dup_x1: - a = xpop(); - b = xpop(); - xpush(a); - xpush(b); - xpush(a); - break; - case Bytecodes::_dup_x2: - a = xpop(); - b = xpop(); - c = xpop(); - xpush(a); - xpush(c); - xpush(b); - xpush(a); - break; - case Bytecodes::_dup2: - a = xpop(); - b = xpop(); - xpush(b); - xpush(a); - xpush(b); - xpush(a); - break; - case Bytecodes::_dup2_x1: - a = xpop(); - b = xpop(); - c = xpop(); - xpush(b); - xpush(a); - xpush(c); - xpush(b); - xpush(a); - break; - case Bytecodes::_dup2_x2: - a = xpop(); - b = xpop(); - c = xpop(); - d = xpop(); - xpush(b); - xpush(a); - xpush(d); - xpush(c); - xpush(b); - xpush(a); - break; - - case Bytecodes::_arraylength: - do_arraylength(); - break; - - case Bytecodes::_getfield: - do_getfield(); - break; - case Bytecodes::_getstatic: - do_getstatic(); - break; - case Bytecodes::_putfield: - do_putfield(); - break; - case Bytecodes::_putstatic: - do_putstatic(); - break; - - case Bytecodes::_iadd: - b = pop(); - a = pop(); - push(SharkValue::create_jint( - builder()->CreateAdd(a->jint_value(), b->jint_value()), false)); - break; - case Bytecodes::_isub: - b = pop(); - a = pop(); - push(SharkValue::create_jint( - builder()->CreateSub(a->jint_value(), b->jint_value()), false)); - break; - case Bytecodes::_imul: - b = pop(); - a = pop(); - push(SharkValue::create_jint( - builder()->CreateMul(a->jint_value(), b->jint_value()), false)); - break; - case Bytecodes::_idiv: - do_idiv(); - break; - case Bytecodes::_irem: - do_irem(); - break; - case Bytecodes::_ineg: - a = pop(); - push(SharkValue::create_jint( - builder()->CreateNeg(a->jint_value()), a->zero_checked())); - break; - case Bytecodes::_ishl: - b = pop(); - a = pop(); - push(SharkValue::create_jint( - builder()->CreateShl( - a->jint_value(), - builder()->CreateAnd( - b->jint_value(), LLVMValue::jint_constant(0x1f))), false)); - break; - case Bytecodes::_ishr: - b = pop(); - a = pop(); - push(SharkValue::create_jint( - builder()->CreateAShr( - a->jint_value(), - builder()->CreateAnd( - b->jint_value(), LLVMValue::jint_constant(0x1f))), false)); - break; - case Bytecodes::_iushr: - b = pop(); - a = pop(); - push(SharkValue::create_jint( - builder()->CreateLShr( - a->jint_value(), - builder()->CreateAnd( - b->jint_value(), LLVMValue::jint_constant(0x1f))), false)); - break; - case Bytecodes::_iand: - b = pop(); - a = pop(); - push(SharkValue::create_jint( - builder()->CreateAnd(a->jint_value(), b->jint_value()), false)); - break; - case Bytecodes::_ior: - b = pop(); - a = pop(); - push(SharkValue::create_jint( - builder()->CreateOr(a->jint_value(), b->jint_value()), - a->zero_checked() && b->zero_checked())); - break; - case Bytecodes::_ixor: - b = pop(); - a = pop(); - push(SharkValue::create_jint( - builder()->CreateXor(a->jint_value(), b->jint_value()), false)); - break; - - case Bytecodes::_ladd: - b = pop(); - a = pop(); - push(SharkValue::create_jlong( - builder()->CreateAdd(a->jlong_value(), b->jlong_value()), false)); - break; - case Bytecodes::_lsub: - b = pop(); - a = pop(); - push(SharkValue::create_jlong( - builder()->CreateSub(a->jlong_value(), b->jlong_value()), false)); - break; - case Bytecodes::_lmul: - b = pop(); - a = pop(); - push(SharkValue::create_jlong( - builder()->CreateMul(a->jlong_value(), b->jlong_value()), false)); - break; - case Bytecodes::_ldiv: - do_ldiv(); - break; - case Bytecodes::_lrem: - do_lrem(); - break; - case Bytecodes::_lneg: - a = pop(); - push(SharkValue::create_jlong( - builder()->CreateNeg(a->jlong_value()), a->zero_checked())); - break; - case Bytecodes::_lshl: - b = pop(); - a = pop(); - push(SharkValue::create_jlong( - builder()->CreateShl( - a->jlong_value(), - builder()->CreateIntCast( - builder()->CreateAnd( - b->jint_value(), LLVMValue::jint_constant(0x3f)), - SharkType::jlong_type(), true)), false)); - break; - case Bytecodes::_lshr: - b = pop(); - a = pop(); - push(SharkValue::create_jlong( - builder()->CreateAShr( - a->jlong_value(), - builder()->CreateIntCast( - builder()->CreateAnd( - b->jint_value(), LLVMValue::jint_constant(0x3f)), - SharkType::jlong_type(), true)), false)); - break; - case Bytecodes::_lushr: - b = pop(); - a = pop(); - push(SharkValue::create_jlong( - builder()->CreateLShr( - a->jlong_value(), - builder()->CreateIntCast( - builder()->CreateAnd( - b->jint_value(), LLVMValue::jint_constant(0x3f)), - SharkType::jlong_type(), true)), false)); - break; - case Bytecodes::_land: - b = pop(); - a = pop(); - push(SharkValue::create_jlong( - builder()->CreateAnd(a->jlong_value(), b->jlong_value()), false)); - break; - case Bytecodes::_lor: - b = pop(); - a = pop(); - push(SharkValue::create_jlong( - builder()->CreateOr(a->jlong_value(), b->jlong_value()), - a->zero_checked() && b->zero_checked())); - break; - case Bytecodes::_lxor: - b = pop(); - a = pop(); - push(SharkValue::create_jlong( - builder()->CreateXor(a->jlong_value(), b->jlong_value()), false)); - break; - - case Bytecodes::_fadd: - b = pop(); - a = pop(); - push(SharkValue::create_jfloat( - builder()->CreateFAdd(a->jfloat_value(), b->jfloat_value()))); - break; - case Bytecodes::_fsub: - b = pop(); - a = pop(); - push(SharkValue::create_jfloat( - builder()->CreateFSub(a->jfloat_value(), b->jfloat_value()))); - break; - case Bytecodes::_fmul: - b = pop(); - a = pop(); - push(SharkValue::create_jfloat( - builder()->CreateFMul(a->jfloat_value(), b->jfloat_value()))); - break; - case Bytecodes::_fdiv: - b = pop(); - a = pop(); - push(SharkValue::create_jfloat( - builder()->CreateFDiv(a->jfloat_value(), b->jfloat_value()))); - break; - case Bytecodes::_frem: - b = pop(); - a = pop(); - push(SharkValue::create_jfloat( - builder()->CreateFRem(a->jfloat_value(), b->jfloat_value()))); - break; - case Bytecodes::_fneg: - a = pop(); - push(SharkValue::create_jfloat( - builder()->CreateFNeg(a->jfloat_value()))); - break; - - case Bytecodes::_dadd: - b = pop(); - a = pop(); - push(SharkValue::create_jdouble( - builder()->CreateFAdd(a->jdouble_value(), b->jdouble_value()))); - break; - case Bytecodes::_dsub: - b = pop(); - a = pop(); - push(SharkValue::create_jdouble( - builder()->CreateFSub(a->jdouble_value(), b->jdouble_value()))); - break; - case Bytecodes::_dmul: - b = pop(); - a = pop(); - push(SharkValue::create_jdouble( - builder()->CreateFMul(a->jdouble_value(), b->jdouble_value()))); - break; - case Bytecodes::_ddiv: - b = pop(); - a = pop(); - push(SharkValue::create_jdouble( - builder()->CreateFDiv(a->jdouble_value(), b->jdouble_value()))); - break; - case Bytecodes::_drem: - b = pop(); - a = pop(); - push(SharkValue::create_jdouble( - builder()->CreateFRem(a->jdouble_value(), b->jdouble_value()))); - break; - case Bytecodes::_dneg: - a = pop(); - push(SharkValue::create_jdouble( - builder()->CreateFNeg(a->jdouble_value()))); - break; - - case Bytecodes::_iinc: - i = iter()->get_index(); - set_local( - i, - SharkValue::create_jint( - builder()->CreateAdd( - LLVMValue::jint_constant(iter()->get_iinc_con()), - local(i)->jint_value()), false)); - break; - - case Bytecodes::_lcmp: - do_lcmp(); - break; - - case Bytecodes::_fcmpl: - do_fcmp(false, false); - break; - case Bytecodes::_fcmpg: - do_fcmp(false, true); - break; - case Bytecodes::_dcmpl: - do_fcmp(true, false); - break; - case Bytecodes::_dcmpg: - do_fcmp(true, true); - break; - - case Bytecodes::_i2l: - a = pop(); - push(SharkValue::create_jlong( - builder()->CreateIntCast( - a->jint_value(), SharkType::jlong_type(), true), a->zero_checked())); - break; - case Bytecodes::_i2f: - push(SharkValue::create_jfloat( - builder()->CreateSIToFP( - pop()->jint_value(), SharkType::jfloat_type()))); - break; - case Bytecodes::_i2d: - push(SharkValue::create_jdouble( - builder()->CreateSIToFP( - pop()->jint_value(), SharkType::jdouble_type()))); - break; - - case Bytecodes::_l2i: - push(SharkValue::create_jint( - builder()->CreateIntCast( - pop()->jlong_value(), SharkType::jint_type(), true), false)); - break; - case Bytecodes::_l2f: - push(SharkValue::create_jfloat( - builder()->CreateSIToFP( - pop()->jlong_value(), SharkType::jfloat_type()))); - break; - case Bytecodes::_l2d: - push(SharkValue::create_jdouble( - builder()->CreateSIToFP( - pop()->jlong_value(), SharkType::jdouble_type()))); - break; - - case Bytecodes::_f2i: - push(SharkValue::create_jint( - builder()->CreateCall( - builder()->f2i(), pop()->jfloat_value()), false)); - break; - case Bytecodes::_f2l: - push(SharkValue::create_jlong( - builder()->CreateCall( - builder()->f2l(), pop()->jfloat_value()), false)); - break; - case Bytecodes::_f2d: - push(SharkValue::create_jdouble( - builder()->CreateFPExt( - pop()->jfloat_value(), SharkType::jdouble_type()))); - break; - - case Bytecodes::_d2i: - push(SharkValue::create_jint( - builder()->CreateCall( - builder()->d2i(), pop()->jdouble_value()), false)); - break; - case Bytecodes::_d2l: - push(SharkValue::create_jlong( - builder()->CreateCall( - builder()->d2l(), pop()->jdouble_value()), false)); - break; - case Bytecodes::_d2f: - push(SharkValue::create_jfloat( - builder()->CreateFPTrunc( - pop()->jdouble_value(), SharkType::jfloat_type()))); - break; - - case Bytecodes::_i2b: - push(SharkValue::create_jint( - builder()->CreateAShr( - builder()->CreateShl( - pop()->jint_value(), - LLVMValue::jint_constant(24)), - LLVMValue::jint_constant(24)), false)); - break; - case Bytecodes::_i2c: - push(SharkValue::create_jint( - builder()->CreateAnd( - pop()->jint_value(), - LLVMValue::jint_constant(0xffff)), false)); - break; - case Bytecodes::_i2s: - push(SharkValue::create_jint( - builder()->CreateAShr( - builder()->CreateShl( - pop()->jint_value(), - LLVMValue::jint_constant(16)), - LLVMValue::jint_constant(16)), false)); - break; - - case Bytecodes::_return: - do_return(T_VOID); - break; - case Bytecodes::_ireturn: - do_return(T_INT); - break; - case Bytecodes::_lreturn: - do_return(T_LONG); - break; - case Bytecodes::_freturn: - do_return(T_FLOAT); - break; - case Bytecodes::_dreturn: - do_return(T_DOUBLE); - break; - case Bytecodes::_areturn: - do_return(T_OBJECT); - break; - - case Bytecodes::_athrow: - do_athrow(); - break; - - case Bytecodes::_goto: - case Bytecodes::_goto_w: - do_goto(); - break; - - case Bytecodes::_jsr: - case Bytecodes::_jsr_w: - do_jsr(); - break; - - case Bytecodes::_ret: - do_ret(); - break; - - case Bytecodes::_ifnull: - do_if(ICmpInst::ICMP_EQ, SharkValue::null(), pop()); - break; - case Bytecodes::_ifnonnull: - do_if(ICmpInst::ICMP_NE, SharkValue::null(), pop()); - break; - case Bytecodes::_if_acmpeq: - b = pop(); - a = pop(); - do_if(ICmpInst::ICMP_EQ, b, a); - break; - case Bytecodes::_if_acmpne: - b = pop(); - a = pop(); - do_if(ICmpInst::ICMP_NE, b, a); - break; - case Bytecodes::_ifeq: - do_if(ICmpInst::ICMP_EQ, SharkValue::jint_constant(0), pop()); - break; - case Bytecodes::_ifne: - do_if(ICmpInst::ICMP_NE, SharkValue::jint_constant(0), pop()); - break; - case Bytecodes::_iflt: - do_if(ICmpInst::ICMP_SLT, SharkValue::jint_constant(0), pop()); - break; - case Bytecodes::_ifle: - do_if(ICmpInst::ICMP_SLE, SharkValue::jint_constant(0), pop()); - break; - case Bytecodes::_ifgt: - do_if(ICmpInst::ICMP_SGT, SharkValue::jint_constant(0), pop()); - break; - case Bytecodes::_ifge: - do_if(ICmpInst::ICMP_SGE, SharkValue::jint_constant(0), pop()); - break; - case Bytecodes::_if_icmpeq: - b = pop(); - a = pop(); - do_if(ICmpInst::ICMP_EQ, b, a); - break; - case Bytecodes::_if_icmpne: - b = pop(); - a = pop(); - do_if(ICmpInst::ICMP_NE, b, a); - break; - case Bytecodes::_if_icmplt: - b = pop(); - a = pop(); - do_if(ICmpInst::ICMP_SLT, b, a); - break; - case Bytecodes::_if_icmple: - b = pop(); - a = pop(); - do_if(ICmpInst::ICMP_SLE, b, a); - break; - case Bytecodes::_if_icmpgt: - b = pop(); - a = pop(); - do_if(ICmpInst::ICMP_SGT, b, a); - break; - case Bytecodes::_if_icmpge: - b = pop(); - a = pop(); - do_if(ICmpInst::ICMP_SGE, b, a); - break; - - case Bytecodes::_tableswitch: - case Bytecodes::_lookupswitch: - do_switch(); - break; - - case Bytecodes::_invokestatic: - case Bytecodes::_invokespecial: - case Bytecodes::_invokevirtual: - case Bytecodes::_invokeinterface: - do_call(); - break; - - case Bytecodes::_instanceof: - // This is a very common construct: - // - // if (object instanceof Klass) { - // something = (Klass) object; - // ... - // } - // - // which gets compiled to something like this: - // - // 28: aload 9 - // 30: instanceof - // 33: ifeq 52 - // 36: aload 9 - // 38: checkcast - // - // Handling both bytecodes at once allows us - // to eliminate the checkcast. - if (iter()->next_bci() < limit && - (iter()->next_bc() == Bytecodes::_ifeq || - iter()->next_bc() == Bytecodes::_ifne) && - (!UseLoopSafepoints || - iter()->next_get_dest() > iter()->next_bci())) { - if (maybe_do_instanceof_if()) { - iter()->next(); - if (SharkTraceBytecodes) - tty->print_cr("%4d: %s", bci(), Bytecodes::name(bc())); - break; - } - } - // fall through - case Bytecodes::_checkcast: - do_instance_check(); - break; - - case Bytecodes::_new: - do_new(); - break; - case Bytecodes::_newarray: - do_newarray(); - break; - case Bytecodes::_anewarray: - do_anewarray(); - break; - case Bytecodes::_multianewarray: - do_multianewarray(); - break; - - case Bytecodes::_monitorenter: - do_monitorenter(); - break; - case Bytecodes::_monitorexit: - do_monitorexit(); - break; - - default: - ShouldNotReachHere(); - } - } -} - -SharkState* SharkBlock::initial_current_state() { - return entry_state()->copy(); -} - -int SharkBlock::switch_default_dest() { - return iter()->get_dest_table(0); -} - -int SharkBlock::switch_table_length() { - switch(bc()) { - case Bytecodes::_tableswitch: - return iter()->get_int_table(2) - iter()->get_int_table(1) + 1; - - case Bytecodes::_lookupswitch: - return iter()->get_int_table(1); - - default: - ShouldNotReachHere(); - } -} - -int SharkBlock::switch_key(int i) { - switch(bc()) { - case Bytecodes::_tableswitch: - return iter()->get_int_table(1) + i; - - case Bytecodes::_lookupswitch: - return iter()->get_int_table(2 + 2 * i); - - default: - ShouldNotReachHere(); - } -} - -int SharkBlock::switch_dest(int i) { - switch(bc()) { - case Bytecodes::_tableswitch: - return iter()->get_dest_table(i + 3); - - case Bytecodes::_lookupswitch: - return iter()->get_dest_table(2 + 2 * i + 1); - - default: - ShouldNotReachHere(); - } -} - -void SharkBlock::do_div_or_rem(bool is_long, bool is_rem) { - SharkValue *sb = pop(); - SharkValue *sa = pop(); - - check_divide_by_zero(sb); - - Value *a, *b, *p, *q; - if (is_long) { - a = sa->jlong_value(); - b = sb->jlong_value(); - p = LLVMValue::jlong_constant(0x8000000000000000LL); - q = LLVMValue::jlong_constant(-1); - } - else { - a = sa->jint_value(); - b = sb->jint_value(); - p = LLVMValue::jint_constant(0x80000000); - q = LLVMValue::jint_constant(-1); - } - - BasicBlock *ip = builder()->GetBlockInsertionPoint(); - BasicBlock *special_case = builder()->CreateBlock(ip, "special_case"); - BasicBlock *general_case = builder()->CreateBlock(ip, "general_case"); - BasicBlock *done = builder()->CreateBlock(ip, "done"); - - builder()->CreateCondBr( - builder()->CreateAnd( - builder()->CreateICmpEQ(a, p), - builder()->CreateICmpEQ(b, q)), - special_case, general_case); - - builder()->SetInsertPoint(special_case); - Value *special_result; - if (is_rem) { - if (is_long) - special_result = LLVMValue::jlong_constant(0); - else - special_result = LLVMValue::jint_constant(0); - } - else { - special_result = a; - } - builder()->CreateBr(done); - - builder()->SetInsertPoint(general_case); - Value *general_result; - if (is_rem) - general_result = builder()->CreateSRem(a, b); - else - general_result = builder()->CreateSDiv(a, b); - builder()->CreateBr(done); - - builder()->SetInsertPoint(done); - PHINode *result; - if (is_long) - result = builder()->CreatePHI(SharkType::jlong_type(), 0, "result"); - else - result = builder()->CreatePHI(SharkType::jint_type(), 0, "result"); - result->addIncoming(special_result, special_case); - result->addIncoming(general_result, general_case); - - if (is_long) - push(SharkValue::create_jlong(result, false)); - else - push(SharkValue::create_jint(result, false)); -} - -void SharkBlock::do_field_access(bool is_get, bool is_field) { - bool will_link; - ciField *field = iter()->get_field(will_link); - assert(will_link, "typeflow responsibility"); - assert(is_field != field->is_static(), "mismatch"); - - // Pop the value off the stack where necessary - SharkValue *value = NULL; - if (!is_get) - value = pop(); - - // Find the object we're accessing, if necessary - Value *object = NULL; - if (is_field) { - SharkValue *value = pop(); - check_null(value); - object = value->generic_value(); - } - if (is_get && field->is_constant() && field->is_static()) { - SharkConstant *constant = SharkConstant::for_field(iter()); - if (constant->is_loaded()) - value = constant->value(builder()); - } - if (!is_get || value == NULL) { - if (!is_field) { - object = builder()->CreateInlineOop(field->holder()->java_mirror()); - } - BasicType basic_type = field->type()->basic_type(); - Type *stack_type = SharkType::to_stackType(basic_type); - Type *field_type = SharkType::to_arrayType(basic_type); - Type *type = field_type; - if (field->is_volatile()) { - if (field_type == SharkType::jfloat_type()) { - type = SharkType::jint_type(); - } else if (field_type == SharkType::jdouble_type()) { - type = SharkType::jlong_type(); - } - } - Value *addr = builder()->CreateAddressOfStructEntry( - object, in_ByteSize(field->offset_in_bytes()), - PointerType::getUnqual(type), - "addr"); - - // Do the access - if (is_get) { - Value* field_value; - if (field->is_volatile()) { - field_value = builder()->CreateAtomicLoad(addr); - field_value = builder()->CreateBitCast(field_value, field_type); - } else { - field_value = builder()->CreateLoad(addr); - } - if (field_type != stack_type) { - field_value = builder()->CreateIntCast( - field_value, stack_type, basic_type != T_CHAR); - } - - value = SharkValue::create_generic(field->type(), field_value, false); - } - else { - Value *field_value = value->generic_value(); - - if (field_type != stack_type) { - field_value = builder()->CreateIntCast( - field_value, field_type, basic_type != T_CHAR); - } - - if (field->is_volatile()) { - field_value = builder()->CreateBitCast(field_value, type); - builder()->CreateAtomicStore(field_value, addr); - } else { - builder()->CreateStore(field_value, addr); - } - - if (!field->type()->is_primitive_type()) { - builder()->CreateUpdateBarrierSet(oopDesc::bs(), addr); - } - } - } - - // Push the value onto the stack where necessary - if (is_get) - push(value); -} - -void SharkBlock::do_lcmp() { - Value *b = pop()->jlong_value(); - Value *a = pop()->jlong_value(); - - BasicBlock *ip = builder()->GetBlockInsertionPoint(); - BasicBlock *ne = builder()->CreateBlock(ip, "lcmp_ne"); - BasicBlock *lt = builder()->CreateBlock(ip, "lcmp_lt"); - BasicBlock *gt = builder()->CreateBlock(ip, "lcmp_gt"); - BasicBlock *done = builder()->CreateBlock(ip, "done"); - - BasicBlock *eq = builder()->GetInsertBlock(); - builder()->CreateCondBr(builder()->CreateICmpEQ(a, b), done, ne); - - builder()->SetInsertPoint(ne); - builder()->CreateCondBr(builder()->CreateICmpSLT(a, b), lt, gt); - - builder()->SetInsertPoint(lt); - builder()->CreateBr(done); - - builder()->SetInsertPoint(gt); - builder()->CreateBr(done); - - builder()->SetInsertPoint(done); - PHINode *result = builder()->CreatePHI(SharkType::jint_type(), 0, "result"); - result->addIncoming(LLVMValue::jint_constant(-1), lt); - result->addIncoming(LLVMValue::jint_constant(0), eq); - result->addIncoming(LLVMValue::jint_constant(1), gt); - - push(SharkValue::create_jint(result, false)); -} - -void SharkBlock::do_fcmp(bool is_double, bool unordered_is_greater) { - Value *a, *b; - if (is_double) { - b = pop()->jdouble_value(); - a = pop()->jdouble_value(); - } - else { - b = pop()->jfloat_value(); - a = pop()->jfloat_value(); - } - - BasicBlock *ip = builder()->GetBlockInsertionPoint(); - BasicBlock *ordered = builder()->CreateBlock(ip, "ordered"); - BasicBlock *ge = builder()->CreateBlock(ip, "fcmp_ge"); - BasicBlock *lt = builder()->CreateBlock(ip, "fcmp_lt"); - BasicBlock *eq = builder()->CreateBlock(ip, "fcmp_eq"); - BasicBlock *gt = builder()->CreateBlock(ip, "fcmp_gt"); - BasicBlock *done = builder()->CreateBlock(ip, "done"); - - builder()->CreateCondBr( - builder()->CreateFCmpUNO(a, b), - unordered_is_greater ? gt : lt, ordered); - - builder()->SetInsertPoint(ordered); - builder()->CreateCondBr(builder()->CreateFCmpULT(a, b), lt, ge); - - builder()->SetInsertPoint(ge); - builder()->CreateCondBr(builder()->CreateFCmpUGT(a, b), gt, eq); - - builder()->SetInsertPoint(lt); - builder()->CreateBr(done); - - builder()->SetInsertPoint(gt); - builder()->CreateBr(done); - - builder()->SetInsertPoint(eq); - builder()->CreateBr(done); - - builder()->SetInsertPoint(done); - PHINode *result = builder()->CreatePHI(SharkType::jint_type(), 0, "result"); - result->addIncoming(LLVMValue::jint_constant(-1), lt); - result->addIncoming(LLVMValue::jint_constant(0), eq); - result->addIncoming(LLVMValue::jint_constant(1), gt); - - push(SharkValue::create_jint(result, false)); -} - -void SharkBlock::emit_IR() { - ShouldNotCallThis(); -} - -SharkState* SharkBlock::entry_state() { - ShouldNotCallThis(); -} - -void SharkBlock::do_zero_check(SharkValue* value) { - ShouldNotCallThis(); -} - -void SharkBlock::maybe_add_backedge_safepoint() { - ShouldNotCallThis(); -} - -bool SharkBlock::has_trap() { - return false; -} - -int SharkBlock::trap_request() { - ShouldNotCallThis(); -} - -int SharkBlock::trap_bci() { - ShouldNotCallThis(); -} - -void SharkBlock::do_trap(int trap_request) { - ShouldNotCallThis(); -} - -void SharkBlock::do_arraylength() { - ShouldNotCallThis(); -} - -void SharkBlock::do_aload(BasicType basic_type) { - ShouldNotCallThis(); -} - -void SharkBlock::do_astore(BasicType basic_type) { - ShouldNotCallThis(); -} - -void SharkBlock::do_return(BasicType type) { - ShouldNotCallThis(); -} - -void SharkBlock::do_athrow() { - ShouldNotCallThis(); -} - -void SharkBlock::do_goto() { - ShouldNotCallThis(); -} - -void SharkBlock::do_jsr() { - ShouldNotCallThis(); -} - -void SharkBlock::do_ret() { - ShouldNotCallThis(); -} - -void SharkBlock::do_if(ICmpInst::Predicate p, SharkValue* b, SharkValue* a) { - ShouldNotCallThis(); -} - -void SharkBlock::do_switch() { - ShouldNotCallThis(); -} - -void SharkBlock::do_call() { - ShouldNotCallThis(); -} - -void SharkBlock::do_instance_check() { - ShouldNotCallThis(); -} - -bool SharkBlock::maybe_do_instanceof_if() { - ShouldNotCallThis(); -} - -void SharkBlock::do_new() { - ShouldNotCallThis(); -} - -void SharkBlock::do_newarray() { - ShouldNotCallThis(); -} - -void SharkBlock::do_anewarray() { - ShouldNotCallThis(); -} - -void SharkBlock::do_multianewarray() { - ShouldNotCallThis(); -} - -void SharkBlock::do_monitorenter() { - ShouldNotCallThis(); -} - -void SharkBlock::do_monitorexit() { - ShouldNotCallThis(); -} diff --git a/src/hotspot/share/shark/sharkBlock.hpp b/src/hotspot/share/shark/sharkBlock.hpp deleted file mode 100644 index 1b43264f1ae..00000000000 --- a/src/hotspot/share/shark/sharkBlock.hpp +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKBLOCK_HPP -#define SHARE_VM_SHARK_SHARKBLOCK_HPP - -#include "ci/ciMethod.hpp" -#include "ci/ciStreams.hpp" -#include "memory/allocation.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkConstant.hpp" -#include "shark/sharkInvariants.hpp" -#include "shark/sharkState.hpp" -#include "shark/sharkValue.hpp" -#include "utilities/debug.hpp" - -class SharkState; - -class SharkBlock : public SharkTargetInvariants { - protected: - SharkBlock(const SharkTargetInvariants* parent) - : SharkTargetInvariants(parent), - _iter(target()), - _current_state(NULL) {} - - SharkBlock(const SharkCompileInvariants* parent, ciMethod* target) - : SharkTargetInvariants(parent, target), - _iter(target), - _current_state(NULL) {} - - private: - ciBytecodeStream _iter; - SharkState* _current_state; - - public: - ciBytecodeStream* iter() { - return &_iter; - } - Bytecodes::Code bc() { - return iter()->cur_bc(); - } - int bci() { - return iter()->cur_bci(); - } - - // Entry state - protected: - virtual SharkState* entry_state(); - - // Current state - private: - SharkState* initial_current_state(); - - public: - SharkState* current_state() { - if (_current_state == NULL) - set_current_state(initial_current_state()); - return _current_state; - } - - protected: - void set_current_state(SharkState* current_state) { - _current_state = current_state; - } - - // Local variables - protected: - SharkValue* local(int index) { - SharkValue *value = current_state()->local(index); - assert(value != NULL, "shouldn't be"); - assert(value->is_one_word() || - (index + 1 < max_locals() && - current_state()->local(index + 1) == NULL), "should be"); - return value; - } - void set_local(int index, SharkValue* value) { - assert(value != NULL, "shouldn't be"); - current_state()->set_local(index, value); - if (value->is_two_word()) - current_state()->set_local(index + 1, NULL); - } - - // Expression stack (raw) - protected: - void xpush(SharkValue* value) { - current_state()->push(value); - } - SharkValue* xpop() { - return current_state()->pop(); - } - SharkValue* xstack(int slot) { - SharkValue *value = current_state()->stack(slot); - assert(value != NULL, "shouldn't be"); - assert(value->is_one_word() || - (slot > 0 && - current_state()->stack(slot - 1) == NULL), "should be"); - return value; - } - int xstack_depth() { - return current_state()->stack_depth(); - } - - // Expression stack (cooked) - protected: - void push(SharkValue* value) { - assert(value != NULL, "shouldn't be"); - xpush(value); - if (value->is_two_word()) - xpush(NULL); - } - SharkValue* pop() { - int size = current_state()->stack(0) == NULL ? 2 : 1; - if (size == 2) - xpop(); - SharkValue *value = xpop(); - assert(value && value->size() == size, "should be"); - return value; - } - SharkValue* pop_result(BasicType type) { - SharkValue *result = pop(); - -#ifdef ASSERT - switch (result->basic_type()) { - case T_BOOLEAN: - case T_BYTE: - case T_CHAR: - case T_SHORT: - assert(type == T_INT, "type mismatch"); - break; - - case T_ARRAY: - assert(type == T_OBJECT, "type mismatch"); - break; - - default: - assert(result->basic_type() == type, "type mismatch"); - } -#endif // ASSERT - - return result; - } - - // Code generation - public: - virtual void emit_IR(); - - protected: - void parse_bytecode(int start, int limit); - - // Helpers - protected: - virtual void do_zero_check(SharkValue* value); - - // Zero checking - protected: - void check_null(SharkValue* object) { - zero_check(object); - } - void check_divide_by_zero(SharkValue* value) { - zero_check(value); - } - private: - void zero_check(SharkValue* value) { - if (!value->zero_checked()) - do_zero_check(value); - } - - // Safepoints - protected: - virtual void maybe_add_backedge_safepoint(); - - // Traps - protected: - virtual bool has_trap(); - virtual int trap_request(); - virtual int trap_bci(); - virtual void do_trap(int trap_request); - - // arraylength - protected: - virtual void do_arraylength(); - - // *aload and *astore - protected: - virtual void do_aload(BasicType basic_type); - virtual void do_astore(BasicType basic_type); - - // *div and *rem - private: - void do_idiv() { - do_div_or_rem(false, false); - } - void do_irem() { - do_div_or_rem(false, true); - } - void do_ldiv() { - do_div_or_rem(true, false); - } - void do_lrem() { - do_div_or_rem(true, true); - } - void do_div_or_rem(bool is_long, bool is_rem); - - // get* and put* - private: - void do_getstatic() { - do_field_access(true, false); - } - void do_getfield() { - do_field_access(true, true); - } - void do_putstatic() { - do_field_access(false, false); - } - void do_putfield() { - do_field_access(false, true); - } - void do_field_access(bool is_get, bool is_field); - - // lcmp and [fd]cmp[lg] - private: - void do_lcmp(); - void do_fcmp(bool is_double, bool unordered_is_greater); - - // *return and athrow - protected: - virtual void do_return(BasicType type); - virtual void do_athrow(); - - // goto* - protected: - virtual void do_goto(); - - // jsr* and ret - protected: - virtual void do_jsr(); - virtual void do_ret(); - - // if* - protected: - virtual void do_if(llvm::ICmpInst::Predicate p, SharkValue* b, SharkValue* a); - - // *switch - protected: - int switch_default_dest(); - int switch_table_length(); - int switch_key(int i); - int switch_dest(int i); - - virtual void do_switch(); - - // invoke* - protected: - virtual void do_call(); - - // checkcast and instanceof - protected: - virtual void do_instance_check(); - virtual bool maybe_do_instanceof_if(); - - // new and *newarray - protected: - virtual void do_new(); - virtual void do_newarray(); - virtual void do_anewarray(); - virtual void do_multianewarray(); - - // monitorenter and monitorexit - protected: - virtual void do_monitorenter(); - virtual void do_monitorexit(); -}; - -#endif // SHARE_VM_SHARK_SHARKBLOCK_HPP diff --git a/src/hotspot/share/shark/sharkBuilder.cpp b/src/hotspot/share/shark/sharkBuilder.cpp deleted file mode 100644 index ab4dcdcefbf..00000000000 --- a/src/hotspot/share/shark/sharkBuilder.cpp +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "ci/ciMethod.hpp" -#include "gc/shared/barrierSet.hpp" -#include "gc/shared/cardTableModRefBS.hpp" -#include "memory/resourceArea.hpp" -#include "oops/method.hpp" -#include "prims/unsafe.hpp" -#include "runtime/os.hpp" -#include "runtime/synchronizer.hpp" -#include "runtime/thread.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/llvmValue.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkContext.hpp" -#include "shark/sharkRuntime.hpp" -#include "utilities/debug.hpp" - -using namespace llvm; - -SharkBuilder::SharkBuilder(SharkCodeBuffer* code_buffer) - : IRBuilder<>(SharkContext::current()), - _code_buffer(code_buffer) { -} - -// Helpers for accessing structures -Value* SharkBuilder::CreateAddressOfStructEntry(Value* base, - ByteSize offset, - Type* type, - const char* name) { - return CreateBitCast(CreateStructGEP(base, in_bytes(offset)), type, name); -} - -LoadInst* SharkBuilder::CreateValueOfStructEntry(Value* base, - ByteSize offset, - Type* type, - const char* name) { - return CreateLoad( - CreateAddressOfStructEntry( - base, offset, PointerType::getUnqual(type)), - name); -} - -// Helpers for accessing arrays - -LoadInst* SharkBuilder::CreateArrayLength(Value* arrayoop) { - return CreateValueOfStructEntry( - arrayoop, in_ByteSize(arrayOopDesc::length_offset_in_bytes()), - SharkType::jint_type(), "length"); -} - -Value* SharkBuilder::CreateArrayAddress(Value* arrayoop, - Type* element_type, - int element_bytes, - ByteSize base_offset, - Value* index, - const char* name) { - Value* offset = CreateIntCast(index, SharkType::intptr_type(), false); - if (element_bytes != 1) - offset = CreateShl( - offset, - LLVMValue::intptr_constant(exact_log2(element_bytes))); - offset = CreateAdd( - LLVMValue::intptr_constant(in_bytes(base_offset)), offset); - - return CreateIntToPtr( - CreateAdd(CreatePtrToInt(arrayoop, SharkType::intptr_type()), offset), - PointerType::getUnqual(element_type), - name); -} - -Value* SharkBuilder::CreateArrayAddress(Value* arrayoop, - BasicType basic_type, - ByteSize base_offset, - Value* index, - const char* name) { - return CreateArrayAddress( - arrayoop, - SharkType::to_arrayType(basic_type), - type2aelembytes(basic_type), - base_offset, index, name); -} - -Value* SharkBuilder::CreateArrayAddress(Value* arrayoop, - BasicType basic_type, - Value* index, - const char* name) { - return CreateArrayAddress( - arrayoop, basic_type, - in_ByteSize(arrayOopDesc::base_offset_in_bytes(basic_type)), - index, name); -} - -// Helpers for creating intrinsics and external functions. - -Type* SharkBuilder::make_type(char type, bool void_ok) { - switch (type) { - // Primitive types - case 'c': - return SharkType::jbyte_type(); - case 'i': - return SharkType::jint_type(); - case 'l': - return SharkType::jlong_type(); - case 'x': - return SharkType::intptr_type(); - case 'f': - return SharkType::jfloat_type(); - case 'd': - return SharkType::jdouble_type(); - - // Pointers to primitive types - case 'C': - case 'I': - case 'L': - case 'X': - case 'F': - case 'D': - return PointerType::getUnqual(make_type(tolower(type), false)); - - // VM objects - case 'T': - return SharkType::thread_type(); - case 'M': - return PointerType::getUnqual(SharkType::monitor_type()); - case 'O': - return SharkType::oop_type(); - case 'K': - return SharkType::klass_type(); - - // Miscellaneous - case 'v': - assert(void_ok, "should be"); - return SharkType::void_type(); - case '1': - return SharkType::bit_type(); - - default: - ShouldNotReachHere(); - } -} - -FunctionType* SharkBuilder::make_ftype(const char* params, - const char* ret) { - std::vector param_types; - for (const char* c = params; *c; c++) - param_types.push_back(make_type(*c, false)); - - assert(strlen(ret) == 1, "should be"); - Type *return_type = make_type(*ret, true); - - return FunctionType::get(return_type, param_types, false); -} - -// Create an object representing an intrinsic or external function by -// referencing the symbol by name. This is the LLVM-style approach, -// but it cannot be used on functions within libjvm.so its symbols -// are not exported. Note that you cannot make this work simply by -// exporting the symbols, as some symbols have the same names as -// symbols in the standard libraries (eg, atan2, fabs) and would -// obscure them were they visible. -Value* SharkBuilder::make_function(const char* name, - const char* params, - const char* ret) { - return SharkContext::current().get_external(name, make_ftype(params, ret)); -} - -// Create an object representing an external function by inlining a -// function pointer in the code. This is not the LLVM way, but it's -// the only way to access functions in libjvm.so and functions like -// __kernel_dmb on ARM which is accessed via an absolute address. -Value* SharkBuilder::make_function(address func, - const char* params, - const char* ret) { - return CreateIntToPtr( - LLVMValue::intptr_constant((intptr_t) func), - PointerType::getUnqual(make_ftype(params, ret))); -} - -// VM calls - -Value* SharkBuilder::find_exception_handler() { - return make_function( - (address) SharkRuntime::find_exception_handler, "TIi", "i"); -} - -Value* SharkBuilder::monitorenter() { - return make_function((address) SharkRuntime::monitorenter, "TM", "v"); -} - -Value* SharkBuilder::monitorexit() { - return make_function((address) SharkRuntime::monitorexit, "TM", "v"); -} - -Value* SharkBuilder::new_instance() { - return make_function((address) SharkRuntime::new_instance, "Ti", "v"); -} - -Value* SharkBuilder::newarray() { - return make_function((address) SharkRuntime::newarray, "Tii", "v"); -} - -Value* SharkBuilder::anewarray() { - return make_function((address) SharkRuntime::anewarray, "Tii", "v"); -} - -Value* SharkBuilder::multianewarray() { - return make_function((address) SharkRuntime::multianewarray, "TiiI", "v"); -} - -Value* SharkBuilder::register_finalizer() { - return make_function((address) SharkRuntime::register_finalizer, "TO", "v"); -} - -Value* SharkBuilder::safepoint() { - return make_function((address) SafepointSynchronize::block, "T", "v"); -} - -Value* SharkBuilder::throw_ArithmeticException() { - return make_function( - (address) SharkRuntime::throw_ArithmeticException, "TCi", "v"); -} - -Value* SharkBuilder::throw_ArrayIndexOutOfBoundsException() { - return make_function( - (address) SharkRuntime::throw_ArrayIndexOutOfBoundsException, "TCii", "v"); -} - -Value* SharkBuilder::throw_ClassCastException() { - return make_function( - (address) SharkRuntime::throw_ClassCastException, "TCi", "v"); -} - -Value* SharkBuilder::throw_NullPointerException() { - return make_function( - (address) SharkRuntime::throw_NullPointerException, "TCi", "v"); -} - -// High-level non-VM calls - -Value* SharkBuilder::f2i() { - return make_function((address) SharedRuntime::f2i, "f", "i"); -} - -Value* SharkBuilder::f2l() { - return make_function((address) SharedRuntime::f2l, "f", "l"); -} - -Value* SharkBuilder::d2i() { - return make_function((address) SharedRuntime::d2i, "d", "i"); -} - -Value* SharkBuilder::d2l() { - return make_function((address) SharedRuntime::d2l, "d", "l"); -} - -Value* SharkBuilder::is_subtype_of() { - return make_function((address) SharkRuntime::is_subtype_of, "KK", "c"); -} - -Value* SharkBuilder::current_time_millis() { - return make_function((address) os::javaTimeMillis, "", "l"); -} - -Value* SharkBuilder::sin() { - return make_function("llvm.sin.f64", "d", "d"); -} - -Value* SharkBuilder::cos() { - return make_function("llvm.cos.f64", "d", "d"); -} - -Value* SharkBuilder::tan() { - return make_function((address) ::tan, "d", "d"); -} - -Value* SharkBuilder::atan2() { - return make_function((address) ::atan2, "dd", "d"); -} - -Value* SharkBuilder::sqrt() { - return make_function("llvm.sqrt.f64", "d", "d"); -} - -Value* SharkBuilder::log() { - return make_function("llvm.log.f64", "d", "d"); -} - -Value* SharkBuilder::log10() { - return make_function("llvm.log10.f64", "d", "d"); -} - -Value* SharkBuilder::pow() { - return make_function("llvm.pow.f64", "dd", "d"); -} - -Value* SharkBuilder::exp() { - return make_function("llvm.exp.f64", "d", "d"); -} - -Value* SharkBuilder::fabs() { - return make_function((address) ::fabs, "d", "d"); -} - -Value* SharkBuilder::unsafe_field_offset_to_byte_offset() { - return make_function((address) Unsafe_field_offset_to_byte_offset, "l", "l"); -} - -Value* SharkBuilder::osr_migration_end() { - return make_function((address) SharedRuntime::OSR_migration_end, "C", "v"); -} - -// Semi-VM calls - -Value* SharkBuilder::throw_StackOverflowError() { - return make_function((address) ZeroStack::handle_overflow, "T", "v"); -} - -Value* SharkBuilder::uncommon_trap() { - return make_function((address) SharkRuntime::uncommon_trap, "Ti", "i"); -} - -Value* SharkBuilder::deoptimized_entry_point() { - return make_function((address) CppInterpreter::main_loop, "iT", "v"); -} - -// Native-Java transition - -Value* SharkBuilder::check_special_condition_for_native_trans() { - return make_function( - (address) JavaThread::check_special_condition_for_native_trans, - "T", "v"); -} - -Value* SharkBuilder::frame_address() { - return make_function("llvm.frameaddress", "i", "C"); -} - -Value* SharkBuilder::memset() { - // LLVM 2.8 added a fifth isVolatile field for memset - // introduced with LLVM r100304 - return make_function("llvm.memset.p0i8.i32", "Cciii", "v"); -} - -Value* SharkBuilder::unimplemented() { - return make_function((address) report_unimplemented, "Ci", "v"); -} - -Value* SharkBuilder::should_not_reach_here() { - return make_function((address) report_should_not_reach_here, "Ci", "v"); -} - -Value* SharkBuilder::dump() { - return make_function((address) SharkRuntime::dump, "Cx", "v"); -} - -// Public interface to low-level non-VM calls - -CallInst* SharkBuilder::CreateGetFrameAddress() { - return CreateCall(frame_address(), LLVMValue::jint_constant(0)); -} - -CallInst* SharkBuilder::CreateMemset(Value* dst, - Value* value, - Value* len, - Value* align) { - return CreateCall5(memset(), dst, value, len, align, - LLVMValue::jint_constant(0)); -} - -CallInst* SharkBuilder::CreateUnimplemented(const char* file, int line) { - return CreateCall2( - unimplemented(), - CreateIntToPtr( - LLVMValue::intptr_constant((intptr_t) file), - PointerType::getUnqual(SharkType::jbyte_type())), - LLVMValue::jint_constant(line)); -} - -CallInst* SharkBuilder::CreateShouldNotReachHere(const char* file, int line) { - return CreateCall2( - should_not_reach_here(), - CreateIntToPtr( - LLVMValue::intptr_constant((intptr_t) file), - PointerType::getUnqual(SharkType::jbyte_type())), - LLVMValue::jint_constant(line)); -} - -#ifndef PRODUCT -CallInst* SharkBuilder::CreateDump(Value* value) { - const char *name; - if (value->hasName()) - // XXX this leaks, but it's only debug code - name = os::strdup(value->getName().str().c_str()); - else - name = "unnamed_value"; - - if (isa(value->getType())) - value = CreatePtrToInt(value, SharkType::intptr_type()); - else if (value->getType()-> - isIntegerTy() - ) - value = CreateIntCast(value, SharkType::intptr_type(), false); - else - Unimplemented(); - - return CreateCall2( - dump(), - CreateIntToPtr( - LLVMValue::intptr_constant((intptr_t) name), - PointerType::getUnqual(SharkType::jbyte_type())), - value); -} -#endif // PRODUCT - -// HotSpot memory barriers - -void SharkBuilder::CreateUpdateBarrierSet(BarrierSet* bs, Value* field) { - if (bs->kind() != BarrierSet::CardTableForRS && - bs->kind() != BarrierSet::CardTableExtension) { - Unimplemented(); - } - - CreateStore( - LLVMValue::jbyte_constant(CardTableModRefBS::dirty_card_val()), - CreateIntToPtr( - CreateAdd( - LLVMValue::intptr_constant( - (intptr_t) (barrier_set_cast(bs)->byte_map_base)), - CreateLShr( - CreatePtrToInt(field, SharkType::intptr_type()), - LLVMValue::intptr_constant(CardTableModRefBS::card_shift))), - PointerType::getUnqual(SharkType::jbyte_type()))); -} - -// Helpers for accessing the code buffer - -Value* SharkBuilder::code_buffer_address(int offset) { - return CreateAdd( - code_buffer()->base_pc(), - LLVMValue::intptr_constant(offset)); -} - -Value* SharkBuilder::CreateInlineOop(jobject object, const char* name) { - return CreateLoad( - CreateIntToPtr( - code_buffer_address(code_buffer()->inline_oop(object)), - PointerType::getUnqual(SharkType::oop_type())), - name); -} - -Value* SharkBuilder::CreateInlineMetadata(Metadata* metadata, llvm::PointerType* type, const char* name) { - assert(metadata != NULL, "inlined metadata must not be NULL"); - assert(metadata->is_metaspace_object(), "sanity check"); - return CreateLoad( - CreateIntToPtr( - code_buffer_address(code_buffer()->inline_Metadata(metadata)), - PointerType::getUnqual(type)), - name); -} - -Value* SharkBuilder::CreateInlineData(void* data, - size_t size, - Type* type, - const char* name) { - return CreateIntToPtr( - code_buffer_address(code_buffer()->inline_data(data, size)), - type, - name); -} - -// Helpers for creating basic blocks. - -BasicBlock* SharkBuilder::GetBlockInsertionPoint() const { - BasicBlock *cur = GetInsertBlock(); - - // BasicBlock::Create takes an insertBefore argument, so - // we need to find the block _after_ the current block - Function::iterator iter = cur->getParent()->begin(); - Function::iterator end = cur->getParent()->end(); - while (iter != end) { - iter++; - if (&*iter == cur) { - iter++; - break; - } - } - - if (iter == end) - return NULL; - else - return iter; -} - -BasicBlock* SharkBuilder::CreateBlock(BasicBlock* ip, const char* name) const { - return BasicBlock::Create( - SharkContext::current(), name, GetInsertBlock()->getParent(), ip); -} - -LoadInst* SharkBuilder::CreateAtomicLoad(Value* ptr, unsigned align, AtomicOrdering ordering, SynchronizationScope synchScope, bool isVolatile, const char* name) { - return Insert(new LoadInst(ptr, name, isVolatile, align, ordering, synchScope), name); -} - -StoreInst* SharkBuilder::CreateAtomicStore(Value* val, Value* ptr, unsigned align, AtomicOrdering ordering, SynchronizationScope synchScope, bool isVolatile, const char* name) { - return Insert(new StoreInst(val, ptr, isVolatile, align, ordering, synchScope), name); -} diff --git a/src/hotspot/share/shark/sharkBuilder.hpp b/src/hotspot/share/shark/sharkBuilder.hpp deleted file mode 100644 index 2f3d27be8e8..00000000000 --- a/src/hotspot/share/shark/sharkBuilder.hpp +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKBUILDER_HPP -#define SHARE_VM_SHARK_SHARKBUILDER_HPP - -#include "ci/ciType.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/llvmValue.hpp" -#include "shark/sharkCodeBuffer.hpp" -#include "shark/sharkEntry.hpp" -#include "shark/sharkType.hpp" -#include "shark/sharkValue.hpp" -#include "utilities/debug.hpp" -#include "utilities/sizes.hpp" - -class BarrierSet; - -class SharkBuilder : public llvm::IRBuilder<> { - friend class SharkCompileInvariants; - - public: - SharkBuilder(SharkCodeBuffer* code_buffer); - - // The code buffer we are building into. - private: - SharkCodeBuffer* _code_buffer; - - protected: - SharkCodeBuffer* code_buffer() const { - return _code_buffer; - } - - public: - llvm::LoadInst* CreateAtomicLoad(llvm::Value* ptr, - unsigned align = HeapWordSize, - llvm::AtomicOrdering ordering = llvm::SequentiallyConsistent, - llvm::SynchronizationScope synchScope = llvm::CrossThread, - bool isVolatile = true, - const char *name = ""); - llvm::StoreInst* CreateAtomicStore(llvm::Value *val, - llvm::Value *ptr, - unsigned align = HeapWordSize, - llvm::AtomicOrdering ordering = llvm::SequentiallyConsistent, - llvm::SynchronizationScope SynchScope = llvm::CrossThread, - bool isVolatile = true, - const char *name = ""); - - // Helpers for accessing structures. - public: - llvm::Value* CreateAddressOfStructEntry(llvm::Value* base, - ByteSize offset, - llvm::Type* type, - const char *name = ""); - llvm::LoadInst* CreateValueOfStructEntry(llvm::Value* base, - ByteSize offset, - llvm::Type* type, - const char *name = ""); - - // Helpers for accessing arrays. - public: - llvm::LoadInst* CreateArrayLength(llvm::Value* arrayoop); - llvm::Value* CreateArrayAddress(llvm::Value* arrayoop, - llvm::Type* element_type, - int element_bytes, - ByteSize base_offset, - llvm::Value* index, - const char* name = ""); - llvm::Value* CreateArrayAddress(llvm::Value* arrayoop, - BasicType basic_type, - ByteSize base_offset, - llvm::Value* index, - const char* name = ""); - llvm::Value* CreateArrayAddress(llvm::Value* arrayoop, - BasicType basic_type, - llvm::Value* index, - const char* name = ""); - - // Helpers for creating intrinsics and external functions. - private: - static llvm::Type* make_type(char type, bool void_ok); - static llvm::FunctionType* make_ftype(const char* params, - const char* ret); - llvm::Value* make_function(const char* name, - const char* params, - const char* ret); - llvm::Value* make_function(address func, - const char* params, - const char* ret); - - // Intrinsics and external functions, part 1: VM calls. - // These are functions declared with JRT_ENTRY and JRT_EXIT, - // macros which flip the thread from _thread_in_Java to - // _thread_in_vm and back. VM calls always safepoint, and can - // therefore throw exceptions. VM calls require of setup and - // teardown, and must be called with SharkTopLevelBlock::call_vm. - public: - llvm::Value* find_exception_handler(); - llvm::Value* monitorenter(); - llvm::Value* monitorexit(); - llvm::Value* new_instance(); - llvm::Value* newarray(); - llvm::Value* anewarray(); - llvm::Value* multianewarray(); - llvm::Value* register_finalizer(); - llvm::Value* safepoint(); - llvm::Value* throw_ArithmeticException(); - llvm::Value* throw_ArrayIndexOutOfBoundsException(); - llvm::Value* throw_ClassCastException(); - llvm::Value* throw_NullPointerException(); - - // Intrinsics and external functions, part 2: High-level non-VM calls. - // These are called like normal functions. The stack is not set - // up for walking so they must not safepoint or throw exceptions, - // or call anything that might. - public: - llvm::Value* f2i(); - llvm::Value* f2l(); - llvm::Value* d2i(); - llvm::Value* d2l(); - llvm::Value* is_subtype_of(); - llvm::Value* current_time_millis(); - llvm::Value* sin(); - llvm::Value* cos(); - llvm::Value* tan(); - llvm::Value* atan2(); - llvm::Value* sqrt(); - llvm::Value* log(); - llvm::Value* log10(); - llvm::Value* pow(); - llvm::Value* exp(); - llvm::Value* fabs(); - llvm::Value* unsafe_field_offset_to_byte_offset(); - llvm::Value* osr_migration_end(); - - // Intrinsics and external functions, part 3: semi-VM calls. - // These are special cases that do VM call stuff but are invoked - // as though they were normal calls. This is acceptable so long - // as the method that calls them returns to its immediately that - // the semi VM call returns. - public: - llvm::Value* throw_StackOverflowError(); - llvm::Value* uncommon_trap(); - llvm::Value* deoptimized_entry_point(); - - // Intrinsics and external functions, part 4: Native-Java transition. - // This is a special case in that it is invoked during a thread - // state transition. The stack must be set up for walking, and it - // may throw exceptions, but the state is _thread_in_native_trans. - public: - llvm::Value* check_special_condition_for_native_trans(); - - // Intrinsics and external functions, part 5: Low-level non-VM calls. - // These have the same caveats as the high-level non-VM calls - // above. They are not accessed directly; rather, you should - // access them via the various Create* methods below. - private: - llvm::Value* cmpxchg_int(); - llvm::Value* cmpxchg_ptr(); - llvm::Value* frame_address(); - llvm::Value* memset(); - llvm::Value* unimplemented(); - llvm::Value* should_not_reach_here(); - llvm::Value* dump(); - - // Public interface to low-level non-VM calls. - public: - llvm::CallInst* CreateGetFrameAddress(); - llvm::CallInst* CreateMemset(llvm::Value* dst, - llvm::Value* value, - llvm::Value* len, - llvm::Value* align); - llvm::CallInst* CreateUnimplemented(const char* file, int line); - llvm::CallInst* CreateShouldNotReachHere(const char* file, int line); - NOT_PRODUCT(llvm::CallInst* CreateDump(llvm::Value* value)); - - // HotSpot memory barriers - public: - void CreateUpdateBarrierSet(BarrierSet* bs, llvm::Value* field); - - // Helpers for accessing the code buffer. - public: - llvm::Value* code_buffer_address(int offset); - llvm::Value* CreateInlineOop(jobject object, const char* name = ""); - llvm::Value* CreateInlineOop(ciObject* object, const char* name = "") { - return CreateInlineOop(object->constant_encoding(), name); - } - - llvm::Value* CreateInlineMetadata(Metadata* metadata, llvm::PointerType* type, const char* name = ""); - llvm::Value* CreateInlineMetadata(ciMetadata* metadata, llvm::PointerType* type, const char* name = "") { - return CreateInlineMetadata(metadata->constant_encoding(), type, name); - } - llvm::Value* CreateInlineData(void* data, - size_t size, - llvm::Type* type, - const char* name = ""); - - // Helpers for creating basic blocks. - // NB don't use unless SharkFunction::CreateBlock is unavailable. - // XXX these are hacky and should be removed. - public: - llvm::BasicBlock* GetBlockInsertionPoint() const; - llvm::BasicBlock* CreateBlock(llvm::BasicBlock* ip, - const char* name="") const; -}; - #endif // SHARE_VM_SHARK_SHARKBUILDER_HPP diff --git a/src/hotspot/share/shark/sharkCacheDecache.cpp b/src/hotspot/share/shark/sharkCacheDecache.cpp deleted file mode 100644 index b63ffeffac9..00000000000 --- a/src/hotspot/share/shark/sharkCacheDecache.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "ci/ciMethod.hpp" -#include "code/debugInfoRec.hpp" -#include "shark/llvmValue.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkCacheDecache.hpp" -#include "shark/sharkFunction.hpp" -#include "shark/sharkState.hpp" - -using namespace llvm; - -void SharkDecacher::start_frame() { - // Start recording the debug information - _pc_offset = code_buffer()->create_unique_offset(); - _oopmap = new OopMap( - oopmap_slot_munge(stack()->oopmap_frame_size()), - oopmap_slot_munge(arg_size())); - debug_info()->add_safepoint(pc_offset(), oopmap()); -} - -void SharkDecacher::start_stack(int stack_depth) { - // Create the array we'll record our stack slots in - _exparray = new GrowableArray(stack_depth); - - // Set the stack pointer - stack()->CreateStoreStackPointer( - builder()->CreatePtrToInt( - stack()->slot_addr( - stack()->stack_slots_offset() + max_stack() - stack_depth), - SharkType::intptr_type())); -} - -void SharkDecacher::process_stack_slot(int index, - SharkValue** addr, - int offset) { - SharkValue *value = *addr; - - // Write the value to the frame if necessary - if (stack_slot_needs_write(index, value)) { - write_value_to_frame( - SharkType::to_stackType(value->basic_type()), - value->generic_value(), - adjusted_offset(value, offset)); - } - - // Record the value in the oopmap if necessary - if (stack_slot_needs_oopmap(index, value)) { - oopmap()->set_oop(slot2reg(offset)); - } - - // Record the value in the debuginfo if necessary - if (stack_slot_needs_debuginfo(index, value)) { - exparray()->append(slot2lv(offset, stack_location_type(index, addr))); - } -} - -void SharkDecacher::start_monitors(int num_monitors) { - // Create the array we'll record our monitors in - _monarray = new GrowableArray(num_monitors); -} - -void SharkDecacher::process_monitor(int index, int box_offset, int obj_offset) { - oopmap()->set_oop(slot2reg(obj_offset)); - - monarray()->append(new MonitorValue( - slot2lv (obj_offset, Location::oop), - slot2loc(box_offset, Location::normal))); -} - -void SharkDecacher::process_oop_tmp_slot(Value** value, int offset) { - // Decache the temporary oop slot - if (*value) { - write_value_to_frame( - SharkType::oop_type(), - *value, - offset); - - oopmap()->set_oop(slot2reg(offset)); - } -} - -void SharkDecacher::process_method_slot(Value** value, int offset) { - // Decache the method pointer - write_value_to_frame( - SharkType::Method_type(), - *value, - offset); - -} - -void SharkDecacher::process_pc_slot(int offset) { - // Record the PC - builder()->CreateStore( - builder()->code_buffer_address(pc_offset()), - stack()->slot_addr(offset)); -} - -void SharkDecacher::start_locals() { - // Create the array we'll record our local variables in - _locarray = new GrowableArray(max_locals());} - -void SharkDecacher::process_local_slot(int index, - SharkValue** addr, - int offset) { - SharkValue *value = *addr; - - // Write the value to the frame if necessary - if (local_slot_needs_write(index, value)) { - write_value_to_frame( - SharkType::to_stackType(value->basic_type()), - value->generic_value(), - adjusted_offset(value, offset)); - } - - // Record the value in the oopmap if necessary - if (local_slot_needs_oopmap(index, value)) { - oopmap()->set_oop(slot2reg(offset)); - } - - // Record the value in the debuginfo if necessary - if (local_slot_needs_debuginfo(index, value)) { - locarray()->append(slot2lv(offset, local_location_type(index, addr))); - } -} - -void SharkDecacher::end_frame() { - // Record the scope - methodHandle null_mh; - debug_info()->describe_scope( - pc_offset(), - null_mh, - target(), - bci(), - true, - false, - false, - debug_info()->create_scope_values(locarray()), - debug_info()->create_scope_values(exparray()), - debug_info()->create_monitor_values(monarray())); - - // Finish recording the debug information - debug_info()->end_safepoint(pc_offset()); -} - -void SharkCacher::process_stack_slot(int index, - SharkValue** addr, - int offset) { - SharkValue *value = *addr; - - // Read the value from the frame if necessary - if (stack_slot_needs_read(index, value)) { - *addr = SharkValue::create_generic( - value->type(), - read_value_from_frame( - SharkType::to_stackType(value->basic_type()), - adjusted_offset(value, offset)), - value->zero_checked()); - } -} - -void SharkOSREntryCacher::process_monitor(int index, - int box_offset, - int obj_offset) { - // Copy the monitor from the OSR buffer to the frame - int src_offset = max_locals() + index * 2; - builder()->CreateStore( - builder()->CreateLoad( - CreateAddressOfOSRBufEntry(src_offset, SharkType::intptr_type())), - stack()->slot_addr(box_offset, SharkType::intptr_type())); - builder()->CreateStore( - builder()->CreateLoad( - CreateAddressOfOSRBufEntry(src_offset + 1, SharkType::oop_type())), - stack()->slot_addr(obj_offset, SharkType::oop_type())); -} - -void SharkCacher::process_oop_tmp_slot(Value** value, int offset) { - // Cache the temporary oop - if (*value) - *value = read_value_from_frame(SharkType::oop_type(), offset); -} - -void SharkCacher::process_method_slot(Value** value, int offset) { - // Cache the method pointer - *value = read_value_from_frame(SharkType::Method_type(), offset); -} - -void SharkFunctionEntryCacher::process_method_slot(Value** value, int offset) { - // "Cache" the method pointer - *value = method(); -} - -void SharkCacher::process_local_slot(int index, - SharkValue** addr, - int offset) { - SharkValue *value = *addr; - - // Read the value from the frame if necessary - if (local_slot_needs_read(index, value)) { - *addr = SharkValue::create_generic( - value->type(), - read_value_from_frame( - SharkType::to_stackType(value->basic_type()), - adjusted_offset(value, offset)), - value->zero_checked()); - } -} - -Value* SharkOSREntryCacher::CreateAddressOfOSRBufEntry(int offset, - Type* type) { - Value *result = builder()->CreateStructGEP(osr_buf(), offset); - if (type != SharkType::intptr_type()) - result = builder()->CreateBitCast(result, PointerType::getUnqual(type)); - return result; -} - -void SharkOSREntryCacher::process_local_slot(int index, - SharkValue** addr, - int offset) { - SharkValue *value = *addr; - - // Read the value from the OSR buffer if necessary - if (local_slot_needs_read(index, value)) { - *addr = SharkValue::create_generic( - value->type(), - builder()->CreateLoad( - CreateAddressOfOSRBufEntry( - adjusted_offset(value, max_locals() - 1 - index), - SharkType::to_stackType(value->basic_type()))), - value->zero_checked()); - } -} - -void SharkDecacher::write_value_to_frame(Type* type, - Value* value, - int offset) { - builder()->CreateStore(value, stack()->slot_addr(offset, type)); -} - -Value* SharkCacher::read_value_from_frame(Type* type, int offset) { - return builder()->CreateLoad(stack()->slot_addr(offset, type)); -} diff --git a/src/hotspot/share/shark/sharkCacheDecache.hpp b/src/hotspot/share/shark/sharkCacheDecache.hpp deleted file mode 100644 index bdc77a55dcc..00000000000 --- a/src/hotspot/share/shark/sharkCacheDecache.hpp +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKCACHEDECACHE_HPP -#define SHARE_VM_SHARK_SHARKCACHEDECACHE_HPP - -#include "ci/ciMethod.hpp" -#include "code/debugInfoRec.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkFunction.hpp" -#include "shark/sharkStateScanner.hpp" - -// Class hierarchy: -// - SharkStateScanner -// - SharkCacherDecacher -// - SharkDecacher -// - SharkJavaCallDecacher -// - SharkVMCallDecacher -// - SharkTrapDecacher -// - SharkCacher -// - SharkJavaCallCacher -// - SharkVMCallCacher -// - SharkFunctionEntryCacher -// - SharkNormalEntryCacher -// - SharkOSREntryCacher - -class SharkCacherDecacher : public SharkStateScanner { - protected: - SharkCacherDecacher(SharkFunction* function) - : SharkStateScanner(function) {} - - // Helper - protected: - static int adjusted_offset(SharkValue* value, int offset) { - if (value->is_two_word()) - offset--; - return offset; - } -}; - -class SharkDecacher : public SharkCacherDecacher { - protected: - SharkDecacher(SharkFunction* function, int bci) - : SharkCacherDecacher(function), _bci(bci) {} - - private: - int _bci; - - protected: - int bci() const { - return _bci; - } - - private: - int _pc_offset; - OopMap* _oopmap; - GrowableArray* _exparray; - GrowableArray* _monarray; - GrowableArray* _locarray; - - private: - int pc_offset() const { - return _pc_offset; - } - OopMap* oopmap() const { - return _oopmap; - } - GrowableArray* exparray() const { - return _exparray; - } - GrowableArray* monarray() const { - return _monarray; - } - GrowableArray* locarray() const { - return _locarray; - } - - // Callbacks - protected: - void start_frame(); - - void start_stack(int stack_depth); - void process_stack_slot(int index, SharkValue** value, int offset); - - void start_monitors(int num_monitors); - void process_monitor(int index, int box_offset, int obj_offset); - - void process_oop_tmp_slot(llvm::Value** value, int offset); - void process_method_slot(llvm::Value** value, int offset); - void process_pc_slot(int offset); - - void start_locals(); - void process_local_slot(int index, SharkValue** value, int offset); - - void end_frame(); - - // oopmap and debuginfo helpers - private: - static int oopmap_slot_munge(int offset) { - return SharkStack::oopmap_slot_munge(offset); - } - static VMReg slot2reg(int offset) { - return SharkStack::slot2reg(offset); - } - static Location slot2loc(int offset, Location::Type type) { - return Location::new_stk_loc(type, offset * wordSize); - } - static LocationValue* slot2lv(int offset, Location::Type type) { - return new LocationValue(slot2loc(offset, type)); - } - static Location::Type location_type(SharkValue** addr, bool maybe_two_word) { - // low addresses this end - // Type 32-bit 64-bit - // ---------------------------------------------------- - // stack[0] local[3] jobject oop oop - // stack[1] local[2] NULL normal lng - // stack[2] local[1] jlong normal invalid - // stack[3] local[0] jint normal normal - // - // high addresses this end - - SharkValue *value = *addr; - if (value) { - if (value->is_jobject()) - return Location::oop; -#ifdef _LP64 - if (value->is_two_word()) - return Location::invalid; -#endif // _LP64 - return Location::normal; - } - else { - if (maybe_two_word) { - value = *(addr - 1); - if (value && value->is_two_word()) { -#ifdef _LP64 - if (value->is_jlong()) - return Location::lng; - if (value->is_jdouble()) - return Location::dbl; - ShouldNotReachHere(); -#else - return Location::normal; -#endif // _LP64 - } - } - return Location::invalid; - } - } - - // Stack slot helpers - protected: - virtual bool stack_slot_needs_write(int index, SharkValue* value) = 0; - virtual bool stack_slot_needs_oopmap(int index, SharkValue* value) = 0; - virtual bool stack_slot_needs_debuginfo(int index, SharkValue* value) = 0; - - static Location::Type stack_location_type(int index, SharkValue** addr) { - return location_type(addr, *addr == NULL); - } - - // Local slot helpers - protected: - virtual bool local_slot_needs_write(int index, SharkValue* value) = 0; - virtual bool local_slot_needs_oopmap(int index, SharkValue* value) = 0; - virtual bool local_slot_needs_debuginfo(int index, SharkValue* value) = 0; - - static Location::Type local_location_type(int index, SharkValue** addr) { - return location_type(addr, index > 0); - } - - // Writer helper - protected: - void write_value_to_frame(llvm::Type* type, - llvm::Value* value, - int offset); -}; - -class SharkJavaCallDecacher : public SharkDecacher { - public: - SharkJavaCallDecacher(SharkFunction* function, int bci, ciMethod* callee) - : SharkDecacher(function, bci), _callee(callee) {} - - private: - ciMethod* _callee; - - protected: - ciMethod* callee() const { - return _callee; - } - - // Stack slot helpers - protected: - bool stack_slot_needs_write(int index, SharkValue* value) { - return value && (index < callee()->arg_size() || value->is_jobject()); - } - bool stack_slot_needs_oopmap(int index, SharkValue* value) { - return value && value->is_jobject() && index >= callee()->arg_size(); - } - bool stack_slot_needs_debuginfo(int index, SharkValue* value) { - return index >= callee()->arg_size(); - } - - // Local slot helpers - protected: - bool local_slot_needs_write(int index, SharkValue* value) { - return value && value->is_jobject(); - } - bool local_slot_needs_oopmap(int index, SharkValue* value) { - return value && value->is_jobject(); - } - bool local_slot_needs_debuginfo(int index, SharkValue* value) { - return true; - } -}; - -class SharkVMCallDecacher : public SharkDecacher { - public: - SharkVMCallDecacher(SharkFunction* function, int bci) - : SharkDecacher(function, bci) {} - - // Stack slot helpers - protected: - bool stack_slot_needs_write(int index, SharkValue* value) { - return value && value->is_jobject(); - } - bool stack_slot_needs_oopmap(int index, SharkValue* value) { - return value && value->is_jobject(); - } - bool stack_slot_needs_debuginfo(int index, SharkValue* value) { - return true; - } - - // Local slot helpers - protected: - bool local_slot_needs_write(int index, SharkValue* value) { - return value && value->is_jobject(); - } - bool local_slot_needs_oopmap(int index, SharkValue* value) { - return value && value->is_jobject(); - } - bool local_slot_needs_debuginfo(int index, SharkValue* value) { - return true; - } -}; - -class SharkTrapDecacher : public SharkDecacher { - public: - SharkTrapDecacher(SharkFunction* function, int bci) - : SharkDecacher(function, bci) {} - - // Stack slot helpers - protected: - bool stack_slot_needs_write(int index, SharkValue* value) { - return value != NULL; - } - bool stack_slot_needs_oopmap(int index, SharkValue* value) { - return value && value->is_jobject(); - } - bool stack_slot_needs_debuginfo(int index, SharkValue* value) { - return true; - } - - // Local slot helpers - protected: - bool local_slot_needs_write(int index, SharkValue* value) { - return value != NULL; - } - bool local_slot_needs_oopmap(int index, SharkValue* value) { - return value && value->is_jobject(); - } - bool local_slot_needs_debuginfo(int index, SharkValue* value) { - return true; - } -}; - -class SharkCacher : public SharkCacherDecacher { - protected: - SharkCacher(SharkFunction* function) - : SharkCacherDecacher(function) {} - - // Callbacks - protected: - void process_stack_slot(int index, SharkValue** value, int offset); - - void process_oop_tmp_slot(llvm::Value** value, int offset); - virtual void process_method_slot(llvm::Value** value, int offset); - - virtual void process_local_slot(int index, SharkValue** value, int offset); - - // Stack slot helper - protected: - virtual bool stack_slot_needs_read(int index, SharkValue* value) = 0; - - // Local slot helper - protected: - virtual bool local_slot_needs_read(int index, SharkValue* value) { - return value && value->is_jobject(); - } - - // Writer helper - protected: - llvm::Value* read_value_from_frame(llvm::Type* type, int offset); -}; - -class SharkJavaCallCacher : public SharkCacher { - public: - SharkJavaCallCacher(SharkFunction* function, ciMethod* callee) - : SharkCacher(function), _callee(callee) {} - - private: - ciMethod* _callee; - - protected: - ciMethod* callee() const { - return _callee; - } - - // Stack slot helper - protected: - bool stack_slot_needs_read(int index, SharkValue* value) { - return value && (index < callee()->return_type()->size() || - value->is_jobject()); - } -}; - -class SharkVMCallCacher : public SharkCacher { - public: - SharkVMCallCacher(SharkFunction* function) - : SharkCacher(function) {} - - // Stack slot helper - protected: - bool stack_slot_needs_read(int index, SharkValue* value) { - return value && value->is_jobject(); - } -}; - -class SharkFunctionEntryCacher : public SharkCacher { - public: - SharkFunctionEntryCacher(SharkFunction* function, llvm::Value* method) - : SharkCacher(function), _method(method) {} - - private: - llvm::Value* _method; - - private: - llvm::Value* method() const { - return _method; - } - - // Method slot callback - protected: - void process_method_slot(llvm::Value** value, int offset); - - // Stack slot helper - protected: - bool stack_slot_needs_read(int index, SharkValue* value) { - ShouldNotReachHere(); // entry block shouldn't have stack - } - - // Local slot helper - protected: - bool local_slot_needs_read(int index, SharkValue* value) { - return value != NULL; - } -}; - -class SharkNormalEntryCacher : public SharkFunctionEntryCacher { - public: - SharkNormalEntryCacher(SharkFunction* function, llvm::Value* method) - : SharkFunctionEntryCacher(function, method) {} -}; - -class SharkOSREntryCacher : public SharkFunctionEntryCacher { - public: - SharkOSREntryCacher(SharkFunction* function, - llvm::Value* method, - llvm::Value* osr_buf) - : SharkFunctionEntryCacher(function, method), - _osr_buf( - builder()->CreateBitCast( - osr_buf, - llvm::PointerType::getUnqual( - llvm::ArrayType::get( - SharkType::intptr_type(), - max_locals() + max_monitors() * 2)))) {} - - private: - llvm::Value* _osr_buf; - - private: - llvm::Value* osr_buf() const { - return _osr_buf; - } - - // Callbacks - protected: - void process_monitor(int index, int box_offset, int obj_offset); - void process_local_slot(int index, SharkValue** value, int offset); - - // Helper - private: - llvm::Value* CreateAddressOfOSRBufEntry(int offset, llvm::Type* type); -}; - -#endif // SHARE_VM_SHARK_SHARKCACHEDECACHE_HPP diff --git a/src/hotspot/share/shark/sharkCodeBuffer.hpp b/src/hotspot/share/shark/sharkCodeBuffer.hpp deleted file mode 100644 index 68b2506dd75..00000000000 --- a/src/hotspot/share/shark/sharkCodeBuffer.hpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKCODEBUFFER_HPP -#define SHARE_VM_SHARK_SHARKCODEBUFFER_HPP - -#include "asm/codeBuffer.hpp" -#include "memory/allocation.hpp" -#include "shark/llvmHeaders.hpp" - -class SharkCodeBuffer : public StackObj { - public: - SharkCodeBuffer(MacroAssembler* masm) - : _masm(masm), _base_pc(NULL) {} - - private: - MacroAssembler* _masm; - llvm::Value* _base_pc; - - private: - MacroAssembler* masm() const { - return _masm; - } - - public: - llvm::Value* base_pc() const { - return _base_pc; - } - void set_base_pc(llvm::Value* base_pc) { - assert(_base_pc == NULL, "only do this once"); - _base_pc = base_pc; - } - - // Allocate some space in the buffer and return its address. - // This buffer will have been relocated by the time the method - // is installed, so you can't inline the result in code. - public: - void* malloc(size_t size) const { - masm()->align(BytesPerWord); - void *result = masm()->pc(); - masm()->advance(size); - return result; - } - - // Create a unique offset in the buffer. - public: - int create_unique_offset() const { - int offset = masm()->offset(); - masm()->advance(1); - return offset; - } - - // Inline an oop into the buffer and return its offset. - public: - int inline_oop(jobject object) const { - masm()->align(BytesPerWord); - int offset = masm()->offset(); - masm()->store_oop(object); - return offset; - } - - int inline_Metadata(Metadata* metadata) const { - masm()->align(BytesPerWord); - int offset = masm()->offset(); - masm()->store_Metadata(metadata); - return offset; - } - - // Inline a block of non-oop data into the buffer and return its offset. - public: - int inline_data(void *src, size_t size) const { - masm()->align(BytesPerWord); - int offset = masm()->offset(); - void *dst = masm()->pc(); - masm()->advance(size); - memcpy(dst, src, size); - return offset; - } -}; - -#endif // SHARE_VM_SHARK_SHARKCODEBUFFER_HPP diff --git a/src/hotspot/share/shark/sharkCompiler.cpp b/src/hotspot/share/shark/sharkCompiler.cpp deleted file mode 100644 index 16fabaca22f..00000000000 --- a/src/hotspot/share/shark/sharkCompiler.cpp +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010, 2011 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "ci/ciEnv.hpp" -#include "ci/ciMethod.hpp" -#include "code/debugInfoRec.hpp" -#include "code/dependencies.hpp" -#include "code/exceptionHandlerTable.hpp" -#include "code/oopRecorder.hpp" -#include "compiler/abstractCompiler.hpp" -#include "compiler/oopMap.hpp" -#include "memory/resourceArea.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkCodeBuffer.hpp" -#include "shark/sharkCompiler.hpp" -#include "shark/sharkContext.hpp" -#include "shark/sharkEntry.hpp" -#include "shark/sharkFunction.hpp" -#include "shark/sharkMemoryManager.hpp" -#include "shark/sharkNativeWrapper.hpp" -#include "shark/shark_globals.hpp" -#include "utilities/debug.hpp" - -#include - -using namespace llvm; - -namespace { - cl::opt - MCPU("mcpu"); - - cl::list - MAttrs("mattr", - cl::CommaSeparated); -} - -SharkCompiler::SharkCompiler() - : AbstractCompiler(shark) { - // Create the lock to protect the memory manager and execution engine - _execution_engine_lock = new Monitor(Mutex::leaf, "SharkExecutionEngineLock"); - MutexLocker locker(execution_engine_lock()); - - // Make LLVM safe for multithreading - if (!llvm_start_multithreaded()) - fatal("llvm_start_multithreaded() failed"); - - // Initialize the native target - InitializeNativeTarget(); - - // MCJIT require a native AsmPrinter - InitializeNativeTargetAsmPrinter(); - - // Create the two contexts which we'll use - _normal_context = new SharkContext("normal"); - _native_context = new SharkContext("native"); - - // Create the memory manager - _memory_manager = new SharkMemoryManager(); - - // Finetune LLVM for the current host CPU. - StringMap Features; - bool gotCpuFeatures = llvm::sys::getHostCPUFeatures(Features); - std::string cpu("-mcpu=" + llvm::sys::getHostCPUName()); - - std::vector args; - args.push_back(""); // program name - args.push_back(cpu.c_str()); - - std::string mattr("-mattr="); - if(gotCpuFeatures){ - for(StringMap::iterator I = Features.begin(), - E = Features.end(); I != E; ++I){ - if(I->second){ - std::string attr(I->first()); - mattr+="+"+attr+","; - } - } - args.push_back(mattr.c_str()); - } - - args.push_back(0); // terminator - cl::ParseCommandLineOptions(args.size() - 1, (char **) &args[0]); - - // Create the JIT - std::string ErrorMsg; - - EngineBuilder builder(_normal_context->module()); - builder.setMCPU(MCPU); - builder.setMAttrs(MAttrs); - builder.setJITMemoryManager(memory_manager()); - builder.setEngineKind(EngineKind::JIT); - builder.setErrorStr(&ErrorMsg); - if (! fnmatch(SharkOptimizationLevel, "None", 0)) { - tty->print_cr("Shark optimization level set to: None"); - builder.setOptLevel(llvm::CodeGenOpt::None); - } else if (! fnmatch(SharkOptimizationLevel, "Less", 0)) { - tty->print_cr("Shark optimization level set to: Less"); - builder.setOptLevel(llvm::CodeGenOpt::Less); - } else if (! fnmatch(SharkOptimizationLevel, "Aggressive", 0)) { - tty->print_cr("Shark optimization level set to: Aggressive"); - builder.setOptLevel(llvm::CodeGenOpt::Aggressive); - } // else Default is selected by, well, default :-) - _execution_engine = builder.create(); - - if (!execution_engine()) { - if (!ErrorMsg.empty()) - printf("Error while creating Shark JIT: %s\n",ErrorMsg.c_str()); - else - printf("Unknown error while creating Shark JIT\n"); - exit(1); - } - - execution_engine()->addModule(_native_context->module()); - - // All done - set_state(initialized); -} - -void SharkCompiler::initialize() { - ShouldNotCallThis(); -} - -void SharkCompiler::compile_method(ciEnv* env, - ciMethod* target, - int entry_bci, - DirectiveSet* directive) { - assert(is_initialized(), "should be"); - ResourceMark rm; - const char *name = methodname( - target->holder()->name()->as_utf8(), target->name()->as_utf8()); - - // Do the typeflow analysis - ciTypeFlow *flow; - if (entry_bci == InvocationEntryBci) - flow = target->get_flow_analysis(); - else - flow = target->get_osr_flow_analysis(entry_bci); - if (flow->failing()) - return; - if (SharkPrintTypeflowOf != NULL) { - if (!fnmatch(SharkPrintTypeflowOf, name, 0)) - flow->print_on(tty); - } - - // Create the recorders - Arena arena; - env->set_oop_recorder(new OopRecorder(&arena)); - OopMapSet oopmaps; - env->set_debug_info(new DebugInformationRecorder(env->oop_recorder())); - env->debug_info()->set_oopmaps(&oopmaps); - env->set_dependencies(new Dependencies(env)); - - // Create the code buffer and builder - CodeBuffer hscb("Shark", 256 * K, 64 * K); - hscb.initialize_oop_recorder(env->oop_recorder()); - MacroAssembler *masm = new MacroAssembler(&hscb); - SharkCodeBuffer cb(masm); - SharkBuilder builder(&cb); - - // Emit the entry point - SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry)); - - // Build the LLVM IR for the method - Function *function = SharkFunction::build(env, &builder, flow, name); - if (env->failing()) { - return; - } - - // Generate native code. It's unpleasant that we have to drop into - // the VM to do this -- it blocks safepoints -- but I can't see any - // other way to handle the locking. - { - ThreadInVMfromNative tiv(JavaThread::current()); - generate_native_code(entry, function, name); - } - - // Install the method into the VM - CodeOffsets offsets; - offsets.set_value(CodeOffsets::Deopt, 0); - offsets.set_value(CodeOffsets::Exceptions, 0); - offsets.set_value(CodeOffsets::Verified_Entry, - target->is_static() ? 0 : wordSize); - - ExceptionHandlerTable handler_table; - ImplicitExceptionTable inc_table; - - env->register_method(target, - entry_bci, - &offsets, - 0, - &hscb, - 0, - &oopmaps, - &handler_table, - &inc_table, - this, - false, - directive(), - false); -} - -nmethod* SharkCompiler::generate_native_wrapper(MacroAssembler* masm, - const methodHandle& target, - int compile_id, - BasicType* arg_types, - BasicType return_type) { - assert(is_initialized(), "should be"); - ResourceMark rm; - const char *name = methodname( - target->klass_name()->as_utf8(), target->name()->as_utf8()); - - // Create the code buffer and builder - SharkCodeBuffer cb(masm); - SharkBuilder builder(&cb); - - // Emit the entry point - SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry)); - - // Build the LLVM IR for the method - SharkNativeWrapper *wrapper = SharkNativeWrapper::build( - &builder, target, name, arg_types, return_type); - - // Generate native code - generate_native_code(entry, wrapper->function(), name); - - // Return the nmethod for installation in the VM - return nmethod::new_native_nmethod(target, - compile_id, - masm->code(), - 0, - 0, - wrapper->frame_size(), - wrapper->receiver_offset(), - wrapper->lock_offset(), - wrapper->oop_maps()); -} - -void SharkCompiler::generate_native_code(SharkEntry* entry, - Function* function, - const char* name) { - // Print the LLVM bitcode, if requested - if (SharkPrintBitcodeOf != NULL) { - if (!fnmatch(SharkPrintBitcodeOf, name, 0)) - function->dump(); - } - - if (SharkVerifyFunction != NULL) { - if (!fnmatch(SharkVerifyFunction, name, 0)) { - verifyFunction(*function); - } - } - - // Compile to native code - address code = NULL; - context()->add_function(function); - { - MutexLocker locker(execution_engine_lock()); - free_queued_methods(); - -#ifndef NDEBUG -#if SHARK_LLVM_VERSION <= 31 -#define setCurrentDebugType SetCurrentDebugType -#endif - if (SharkPrintAsmOf != NULL) { - if (!fnmatch(SharkPrintAsmOf, name, 0)) { - llvm::setCurrentDebugType(X86_ONLY("x86-emitter") NOT_X86("jit")); - llvm::DebugFlag = true; - } - else { - llvm::setCurrentDebugType(""); - llvm::DebugFlag = false; - } - } -#ifdef setCurrentDebugType -#undef setCurrentDebugType -#endif -#endif // !NDEBUG - memory_manager()->set_entry_for_function(function, entry); - code = (address) execution_engine()->getPointerToFunction(function); - } - assert(code != NULL, "code must be != NULL"); - entry->set_entry_point(code); - entry->set_function(function); - entry->set_context(context()); - address code_start = entry->code_start(); - address code_limit = entry->code_limit(); - - // Register generated code for profiling, etc - if (JvmtiExport::should_post_dynamic_code_generated()) - JvmtiExport::post_dynamic_code_generated(name, code_start, code_limit); - - // Print debug information, if requested - if (SharkTraceInstalls) { - tty->print_cr( - " [%p-%p): %s (%d bytes code)", - code_start, code_limit, name, code_limit - code_start); - } -} - -void SharkCompiler::free_compiled_method(address code) { - // This method may only be called when the VM is at a safepoint. - // All _thread_in_vm threads will be waiting for the safepoint to - // finish with the exception of the VM thread, so we can consider - // ourself the owner of the execution engine lock even though we - // can't actually acquire it at this time. - assert(Thread::current()->is_Compiler_thread(), "must be called by compiler thread"); - assert_locked_or_safepoint(CodeCache_lock); - - SharkEntry *entry = (SharkEntry *) code; - entry->context()->push_to_free_queue(entry->function()); -} - -void SharkCompiler::free_queued_methods() { - // The free queue is protected by the execution engine lock - assert(execution_engine_lock()->owned_by_self(), "should be"); - - while (true) { - Function *function = context()->pop_from_free_queue(); - if (function == NULL) - break; - - execution_engine()->freeMachineCodeForFunction(function); - function->eraseFromParent(); - } -} - -const char* SharkCompiler::methodname(const char* klass, const char* method) { - char *buf = NEW_RESOURCE_ARRAY(char, strlen(klass) + 2 + strlen(method) + 1); - - char *dst = buf; - for (const char *c = klass; *c; c++) { - if (*c == '/') - *(dst++) = '.'; - else - *(dst++) = *c; - } - *(dst++) = ':'; - *(dst++) = ':'; - for (const char *c = method; *c; c++) { - *(dst++) = *c; - } - *(dst++) = '\0'; - return buf; -} - -void SharkCompiler::print_timers() { - // do nothing -} diff --git a/src/hotspot/share/shark/sharkCompiler.hpp b/src/hotspot/share/shark/sharkCompiler.hpp deleted file mode 100644 index 7c4179371d1..00000000000 --- a/src/hotspot/share/shark/sharkCompiler.hpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010, 2011 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKCOMPILER_HPP -#define SHARE_VM_SHARK_SHARKCOMPILER_HPP - -#include "ci/ciEnv.hpp" -#include "ci/ciMethod.hpp" -#include "compiler/abstractCompiler.hpp" -#include "compiler/compileBroker.hpp" -#include "compiler/compilerDirectives.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkMemoryManager.hpp" - -class SharkContext; - -class SharkCompiler : public AbstractCompiler { - public: - // Creation - SharkCompiler(); - - // Name of this compiler - const char *name() { return "shark"; } - - // Missing feature tests - bool supports_native() { return true; } - bool supports_osr() { return true; } - bool can_compile_method(const methodHandle& method) { - return ! (method->is_method_handle_intrinsic() || method->is_compiled_lambda_form()); - } - - // Initialization - void initialize(); - - // Compile a normal (bytecode) method and install it in the VM - void compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* dirset); - - // Print compilation timers and statistics - void print_timers(); - - // Generate a wrapper for a native (JNI) method - nmethod* generate_native_wrapper(MacroAssembler* masm, - const methodHandle& target, - int compile_id, - BasicType* arg_types, - BasicType return_type); - - // Free compiled methods (and native wrappers) - void free_compiled_method(address code); - - // Each thread generating IR needs its own context. The normal - // context is used for bytecode methods, and is protected from - // multiple simultaneous accesses by being restricted to the - // compiler thread. The native context is used for JNI methods, - // and is protected from multiple simultaneous accesses by the - // adapter handler library lock. - private: - SharkContext* _normal_context; - SharkContext* _native_context; - - public: - SharkContext* context() const { - if (JavaThread::current()->is_Compiler_thread()) { - return _normal_context; - } - else { - assert(AdapterHandlerLibrary_lock->owned_by_self(), "should be"); - return _native_context; - } - } - - // The LLVM execution engine is the JIT we use to generate native - // code. It is thread safe, but we need to protect it with a lock - // of our own because otherwise LLVM's lock and HotSpot's locks - // interleave and deadlock. The SharkMemoryManager is not thread - // safe, and is protected by the same lock as the execution engine. - private: - Monitor* _execution_engine_lock; - SharkMemoryManager* _memory_manager; - llvm::ExecutionEngine* _execution_engine; - - private: - Monitor* execution_engine_lock() const { - return _execution_engine_lock; - } - SharkMemoryManager* memory_manager() const { - assert(execution_engine_lock()->owned_by_self(), "should be"); - return _memory_manager; - } - llvm::ExecutionEngine* execution_engine() const { - assert(execution_engine_lock()->owned_by_self(), "should be"); - return _execution_engine; - } - - // Global access - public: - static SharkCompiler* compiler() { - AbstractCompiler *compiler = - CompileBroker::compiler(CompLevel_full_optimization); - assert(compiler->is_shark() && compiler->is_initialized(), "should be"); - return (SharkCompiler *) compiler; - } - - // Helpers - private: - static const char* methodname(const char* klass, const char* method); - void generate_native_code(SharkEntry* entry, - llvm::Function* function, - const char* name); - void free_queued_methods(); -}; - -#endif // SHARE_VM_SHARK_SHARKCOMPILER_HPP diff --git a/src/hotspot/share/shark/sharkConstant.cpp b/src/hotspot/share/shark/sharkConstant.cpp deleted file mode 100644 index 84ce2359e06..00000000000 --- a/src/hotspot/share/shark/sharkConstant.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "ci/ciInstance.hpp" -#include "ci/ciStreams.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkConstant.hpp" -#include "shark/sharkValue.hpp" - -using namespace llvm; - -SharkConstant* SharkConstant::for_ldc(ciBytecodeStream *iter) { - ciConstant constant = iter->get_constant(); - ciType *type = NULL; - if (constant.basic_type() == T_OBJECT) { - ciEnv *env = ciEnv::current(); - - assert(constant.as_object()->klass() == env->String_klass() - || constant.as_object()->klass() == env->Class_klass() - || constant.as_object()->klass()->is_subtype_of(env->MethodType_klass()) - || constant.as_object()->klass()->is_subtype_of(env->MethodHandle_klass()), "should be"); - - type = constant.as_object()->klass(); - } - return new SharkConstant(constant, type); -} - -SharkConstant* SharkConstant::for_field(ciBytecodeStream *iter) { - bool will_link; - ciField *field = iter->get_field(will_link); - assert(will_link, "typeflow responsibility"); - - return new SharkConstant(field->constant_value(), field->type()); -} - -SharkConstant::SharkConstant(ciConstant constant, ciType *type) { - SharkValue *value = NULL; - - switch (constant.basic_type()) { - case T_BOOLEAN: - case T_BYTE: - case T_CHAR: - case T_SHORT: - case T_INT: - value = SharkValue::jint_constant(constant.as_int()); - break; - - case T_LONG: - value = SharkValue::jlong_constant(constant.as_long()); - break; - - case T_FLOAT: - value = SharkValue::jfloat_constant(constant.as_float()); - break; - - case T_DOUBLE: - value = SharkValue::jdouble_constant(constant.as_double()); - break; - - case T_OBJECT: - case T_ARRAY: - break; - - case T_ILLEGAL: - // out of memory - _is_loaded = false; - return; - - default: - tty->print_cr("Unhandled type %s", type2name(constant.basic_type())); - ShouldNotReachHere(); - } - - // Handle primitive types. We create SharkValues for these - // now; doing so doesn't emit any code, and it allows us to - // delegate a bunch of stuff to the SharkValue code. - if (value) { - _value = value; - _is_loaded = true; - _is_nonzero = value->zero_checked(); - _is_two_word = value->is_two_word(); - return; - } - - // Handle reference types. This is tricky because some - // ciObjects are psuedo-objects that refer to oops which - // have yet to be created. We need to spot the unloaded - // objects (which differ between ldc* and get*, thanks!) - ciObject *object = constant.as_object(); - assert(type != NULL, "shouldn't be"); - - if ((! object->is_null_object()) && object->klass() == ciEnv::current()->Class_klass()) { - ciKlass *klass = object->klass(); - if (! klass->is_loaded()) { - _is_loaded = false; - return; - } - } - - if (object->is_null_object() || ! object->can_be_constant() || ! object->is_loaded()) { - _is_loaded = false; - return; - } - - _value = NULL; - _object = object; - _type = type; - _is_loaded = true; - _is_nonzero = true; - _is_two_word = false; -} diff --git a/src/hotspot/share/shark/sharkConstant.hpp b/src/hotspot/share/shark/sharkConstant.hpp deleted file mode 100644 index 2541028f573..00000000000 --- a/src/hotspot/share/shark/sharkConstant.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKCONSTANT_HPP -#define SHARE_VM_SHARK_SHARKCONSTANT_HPP - -#include "ci/ciStreams.hpp" -#include "memory/allocation.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkValue.hpp" - -class SharkConstant : public ResourceObj { - public: - static SharkConstant* for_ldc(ciBytecodeStream* iter); - static SharkConstant* for_field(ciBytecodeStream* iter); - - private: - SharkConstant(ciConstant constant, ciType* type); - - private: - SharkValue* _value; - ciObject* _object; - ciType* _type; - bool _is_loaded; - bool _is_nonzero; - bool _is_two_word; - - public: - bool is_loaded() const { - return _is_loaded; - } - bool is_nonzero() const { - assert(is_loaded(), "should be"); - return _is_nonzero; - } - bool is_two_word() const { - assert(is_loaded(), "should be"); - return _is_two_word; - } - - public: - SharkValue* value(SharkBuilder* builder) { - assert(is_loaded(), "should be"); - if (_value == NULL) { - _value = SharkValue::create_generic( - _type, builder->CreateInlineOop(_object), _is_nonzero); - } - return _value; - } -}; - -#endif // SHARE_VM_SHARK_SHARKCONSTANT_HPP diff --git a/src/hotspot/share/shark/sharkContext.cpp b/src/hotspot/share/shark/sharkContext.cpp deleted file mode 100644 index 0fc86f0b14c..00000000000 --- a/src/hotspot/share/shark/sharkContext.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009, 2010 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "oops/arrayOop.hpp" -#include "oops/oop.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkContext.hpp" -#include "utilities/globalDefinitions.hpp" -#include "memory/allocation.hpp" - -using namespace llvm; - -SharkContext::SharkContext(const char* name) - : LLVMContext(), - _free_queue(NULL) { - // Create a module to build our functions into - _module = new Module(name, *this); - - // Create basic types - _void_type = Type::getVoidTy(*this); - _bit_type = Type::getInt1Ty(*this); - _jbyte_type = Type::getInt8Ty(*this); - _jshort_type = Type::getInt16Ty(*this); - _jint_type = Type::getInt32Ty(*this); - _jlong_type = Type::getInt64Ty(*this); - _jfloat_type = Type::getFloatTy(*this); - _jdouble_type = Type::getDoubleTy(*this); - - // Create compound types - _itableOffsetEntry_type = PointerType::getUnqual( - ArrayType::get(jbyte_type(), itableOffsetEntry::size() * wordSize)); - - _Metadata_type = PointerType::getUnqual( - ArrayType::get(jbyte_type(), sizeof(Metadata))); - - _klass_type = PointerType::getUnqual( - ArrayType::get(jbyte_type(), sizeof(Klass))); - - _jniEnv_type = PointerType::getUnqual( - ArrayType::get(jbyte_type(), sizeof(JNIEnv))); - - _jniHandleBlock_type = PointerType::getUnqual( - ArrayType::get(jbyte_type(), sizeof(JNIHandleBlock))); - - _Method_type = PointerType::getUnqual( - ArrayType::get(jbyte_type(), sizeof(Method))); - - _monitor_type = ArrayType::get( - jbyte_type(), frame::interpreter_frame_monitor_size() * wordSize); - - _oop_type = PointerType::getUnqual( - ArrayType::get(jbyte_type(), sizeof(oopDesc))); - - _thread_type = PointerType::getUnqual( - ArrayType::get(jbyte_type(), sizeof(JavaThread))); - - _zeroStack_type = PointerType::getUnqual( - ArrayType::get(jbyte_type(), sizeof(ZeroStack))); - - std::vector params; - params.push_back(Method_type()); - params.push_back(intptr_type()); - params.push_back(thread_type()); - _entry_point_type = FunctionType::get(jint_type(), params, false); - - params.clear(); - params.push_back(Method_type()); - params.push_back(PointerType::getUnqual(jbyte_type())); - params.push_back(intptr_type()); - params.push_back(thread_type()); - _osr_entry_point_type = FunctionType::get(jint_type(), params, false); - - // Create mappings - for (int i = 0; i < T_CONFLICT; i++) { - switch (i) { - case T_BOOLEAN: - _to_stackType[i] = jint_type(); - _to_arrayType[i] = jbyte_type(); - break; - - case T_BYTE: - _to_stackType[i] = jint_type(); - _to_arrayType[i] = jbyte_type(); - break; - - case T_CHAR: - _to_stackType[i] = jint_type(); - _to_arrayType[i] = jshort_type(); - break; - - case T_SHORT: - _to_stackType[i] = jint_type(); - _to_arrayType[i] = jshort_type(); - break; - - case T_INT: - _to_stackType[i] = jint_type(); - _to_arrayType[i] = jint_type(); - break; - - case T_LONG: - _to_stackType[i] = jlong_type(); - _to_arrayType[i] = jlong_type(); - break; - - case T_FLOAT: - _to_stackType[i] = jfloat_type(); - _to_arrayType[i] = jfloat_type(); - break; - - case T_DOUBLE: - _to_stackType[i] = jdouble_type(); - _to_arrayType[i] = jdouble_type(); - break; - - case T_OBJECT: - case T_ARRAY: - _to_stackType[i] = oop_type(); - _to_arrayType[i] = oop_type(); - break; - - case T_ADDRESS: - _to_stackType[i] = intptr_type(); - _to_arrayType[i] = NULL; - break; - - default: - _to_stackType[i] = NULL; - _to_arrayType[i] = NULL; - } - } -} - -class SharkFreeQueueItem : public CHeapObj { - public: - SharkFreeQueueItem(llvm::Function* function, SharkFreeQueueItem *next) - : _function(function), _next(next) {} - - private: - llvm::Function* _function; - SharkFreeQueueItem* _next; - - public: - llvm::Function* function() const { - return _function; - } - SharkFreeQueueItem* next() const { - return _next; - } -}; - -void SharkContext::push_to_free_queue(Function* function) { - _free_queue = new SharkFreeQueueItem(function, _free_queue); -} - -Function* SharkContext::pop_from_free_queue() { - if (_free_queue == NULL) - return NULL; - - SharkFreeQueueItem *item = _free_queue; - Function *function = item->function(); - _free_queue = item->next(); - delete item; - return function; -} diff --git a/src/hotspot/share/shark/sharkContext.hpp b/src/hotspot/share/shark/sharkContext.hpp deleted file mode 100644 index 952cf13b7b7..00000000000 --- a/src/hotspot/share/shark/sharkContext.hpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009, 2010 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKCONTEXT_HPP -#define SHARE_VM_SHARK_SHARKCONTEXT_HPP - -#include "shark/llvmHeaders.hpp" -#include "shark/sharkCompiler.hpp" - -// The LLVMContext class allows multiple instances of LLVM to operate -// independently of each other in a multithreaded context. We extend -// this here to store things in Shark that are LLVMContext-specific. - -class SharkFreeQueueItem; - -class SharkContext : public llvm::LLVMContext { - public: - SharkContext(const char* name); - - private: - llvm::Module* _module; - - public: - llvm::Module* module() const { - return _module; - } - - // Get this thread's SharkContext - public: - static SharkContext& current() { - return *SharkCompiler::compiler()->context(); - } - - // Module accessors - public: - void add_function(llvm::Function* function) const { - module()->getFunctionList().push_back(function); - } - llvm::Constant* get_external(const char* name, - llvm::FunctionType* sig) { - return module()->getOrInsertFunction(name, sig); - } - - // Basic types - private: - llvm::Type* _void_type; - llvm::IntegerType* _bit_type; - llvm::IntegerType* _jbyte_type; - llvm::IntegerType* _jshort_type; - llvm::IntegerType* _jint_type; - llvm::IntegerType* _jlong_type; - llvm::Type* _jfloat_type; - llvm::Type* _jdouble_type; - - public: - llvm::Type* void_type() const { - return _void_type; - } - llvm::IntegerType* bit_type() const { - return _bit_type; - } - llvm::IntegerType* jbyte_type() const { - return _jbyte_type; - } - llvm::IntegerType* jshort_type() const { - return _jshort_type; - } - llvm::IntegerType* jint_type() const { - return _jint_type; - } - llvm::IntegerType* jlong_type() const { - return _jlong_type; - } - llvm::Type* jfloat_type() const { - return _jfloat_type; - } - llvm::Type* jdouble_type() const { - return _jdouble_type; - } - llvm::IntegerType* intptr_type() const { - return LP64_ONLY(jlong_type()) NOT_LP64(jint_type()); - } - - // Compound types - private: - llvm::PointerType* _itableOffsetEntry_type; - llvm::PointerType* _jniEnv_type; - llvm::PointerType* _jniHandleBlock_type; - llvm::PointerType* _Metadata_type; - llvm::PointerType* _klass_type; - llvm::PointerType* _Method_type; - llvm::ArrayType* _monitor_type; - llvm::PointerType* _oop_type; - llvm::PointerType* _thread_type; - llvm::PointerType* _zeroStack_type; - llvm::FunctionType* _entry_point_type; - llvm::FunctionType* _osr_entry_point_type; - - public: - llvm::PointerType* itableOffsetEntry_type() const { - return _itableOffsetEntry_type; - } - llvm::PointerType* jniEnv_type() const { - return _jniEnv_type; - } - llvm::PointerType* jniHandleBlock_type() const { - return _jniHandleBlock_type; - } - llvm::PointerType* Metadata_type() const { - return _Metadata_type; - } - llvm::PointerType* klass_type() const { - return _klass_type; - } - llvm::PointerType* Method_type() const { - return _Method_type; - } - llvm::ArrayType* monitor_type() const { - return _monitor_type; - } - llvm::PointerType* oop_type() const { - return _oop_type; - } - llvm::PointerType* thread_type() const { - return _thread_type; - } - llvm::PointerType* zeroStack_type() const { - return _zeroStack_type; - } - llvm::FunctionType* entry_point_type() const { - return _entry_point_type; - } - llvm::FunctionType* osr_entry_point_type() const { - return _osr_entry_point_type; - } - - // Mappings - private: - llvm::Type* _to_stackType[T_CONFLICT]; - llvm::Type* _to_arrayType[T_CONFLICT]; - - private: - llvm::Type* map_type(llvm::Type* const* table, - BasicType type) const { - assert(type >= 0 && type < T_CONFLICT, "unhandled type"); - llvm::Type* result = table[type]; - assert(result != NULL, "unhandled type"); - return result; - } - - public: - llvm::Type* to_stackType(BasicType type) const { - return map_type(_to_stackType, type); - } - llvm::Type* to_arrayType(BasicType type) const { - return map_type(_to_arrayType, type); - } - - // Functions queued for freeing - private: - SharkFreeQueueItem* _free_queue; - - public: - void push_to_free_queue(llvm::Function* function); - llvm::Function* pop_from_free_queue(); -}; - -#endif // SHARE_VM_SHARK_SHARKCONTEXT_HPP diff --git a/src/hotspot/share/shark/sharkFunction.cpp b/src/hotspot/share/shark/sharkFunction.cpp deleted file mode 100644 index ac6fa67b679..00000000000 --- a/src/hotspot/share/shark/sharkFunction.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "ci/ciTypeFlow.hpp" -#include "memory/allocation.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/llvmValue.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkEntry.hpp" -#include "shark/sharkFunction.hpp" -#include "shark/sharkState.hpp" -#include "shark/sharkTopLevelBlock.hpp" -#include "shark/shark_globals.hpp" -#include "utilities/debug.hpp" - -using namespace llvm; - -void SharkFunction::initialize(const char *name) { - // Create the function - _function = Function::Create( - entry_point_type(), - GlobalVariable::InternalLinkage, - name); - - // Get our arguments - Function::arg_iterator ai = function()->arg_begin(); - Argument *method = ai++; - method->setName("method"); - Argument *osr_buf = NULL; - if (is_osr()) { - osr_buf = ai++; - osr_buf->setName("osr_buf"); - } - Argument *base_pc = ai++; - base_pc->setName("base_pc"); - code_buffer()->set_base_pc(base_pc); - Argument *thread = ai++; - thread->setName("thread"); - set_thread(thread); - - // Create the list of blocks - set_block_insertion_point(NULL); - _blocks = NEW_RESOURCE_ARRAY(SharkTopLevelBlock*, block_count()); - for (int i = 0; i < block_count(); i++) { - ciTypeFlow::Block *b = flow()->pre_order_at(i); - - // Work around a bug in pre_order_at() that does not return - // the correct pre-ordering. If pre_order_at() were correct - // this line could simply be: - // _blocks[i] = new SharkTopLevelBlock(this, b); - _blocks[b->pre_order()] = new SharkTopLevelBlock(this, b); - } - - // Walk the tree from the start block to determine which - // blocks are entered and which blocks require phis - SharkTopLevelBlock *start_block = block(flow()->start_block_num()); - if (is_osr() && start_block->stack_depth_at_entry() != 0) { - env()->record_method_not_compilable("can't compile OSR block with incoming stack-depth > 0"); - return; - } - assert(start_block->start() == flow()->start_bci(), "blocks out of order"); - start_block->enter(); - - // Initialize all entered blocks - for (int i = 0; i < block_count(); i++) { - if (block(i)->entered()) - block(i)->initialize(); - } - - // Create and push our stack frame - set_block_insertion_point(&function()->front()); - builder()->SetInsertPoint(CreateBlock()); - _stack = SharkStack::CreateBuildAndPushFrame(this, method); - - // Create the entry state - SharkState *entry_state; - if (is_osr()) { - entry_state = new SharkOSREntryState(start_block, method, osr_buf); - - // Free the OSR buffer - builder()->CreateCall(builder()->osr_migration_end(), osr_buf); - } - else { - entry_state = new SharkNormalEntryState(start_block, method); - - // Lock if necessary - if (is_synchronized()) { - SharkTopLevelBlock *locker = - new SharkTopLevelBlock(this, start_block->ciblock()); - locker->add_incoming(entry_state); - - set_block_insertion_point(start_block->entry_block()); - locker->acquire_method_lock(); - - entry_state = locker->current_state(); - } - } - - // Transition into the method proper - start_block->add_incoming(entry_state); - builder()->CreateBr(start_block->entry_block()); - - // Parse the blocks - for (int i = 0; i < block_count(); i++) { - if (!block(i)->entered()) - continue; - - if (i + 1 < block_count()) - set_block_insertion_point(block(i + 1)->entry_block()); - else - set_block_insertion_point(NULL); - - block(i)->emit_IR(); - } - do_deferred_zero_checks(); -} - -class DeferredZeroCheck : public SharkTargetInvariants { - public: - DeferredZeroCheck(SharkTopLevelBlock* block, SharkValue* value) - : SharkTargetInvariants(block), - _block(block), - _value(value), - _bci(block->bci()), - _state(block->current_state()->copy()), - _check_block(builder()->GetInsertBlock()), - _continue_block(function()->CreateBlock("not_zero")) { - builder()->SetInsertPoint(continue_block()); - } - - private: - SharkTopLevelBlock* _block; - SharkValue* _value; - int _bci; - SharkState* _state; - BasicBlock* _check_block; - BasicBlock* _continue_block; - - public: - SharkTopLevelBlock* block() const { - return _block; - } - SharkValue* value() const { - return _value; - } - int bci() const { - return _bci; - } - SharkState* state() const { - return _state; - } - BasicBlock* check_block() const { - return _check_block; - } - BasicBlock* continue_block() const { - return _continue_block; - } - - public: - SharkFunction* function() const { - return block()->function(); - } - - public: - void process() const { - builder()->SetInsertPoint(check_block()); - block()->do_deferred_zero_check(value(), bci(), state(), continue_block()); - } -}; - -void SharkFunction::add_deferred_zero_check(SharkTopLevelBlock* block, - SharkValue* value) { - deferred_zero_checks()->append(new DeferredZeroCheck(block, value)); -} - -void SharkFunction::do_deferred_zero_checks() { - for (int i = 0; i < deferred_zero_checks()->length(); i++) - deferred_zero_checks()->at(i)->process(); -} diff --git a/src/hotspot/share/shark/sharkFunction.hpp b/src/hotspot/share/shark/sharkFunction.hpp deleted file mode 100644 index 47a480fa14f..00000000000 --- a/src/hotspot/share/shark/sharkFunction.hpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKFUNCTION_HPP -#define SHARE_VM_SHARK_SHARKFUNCTION_HPP - -#include "ci/ciEnv.hpp" -#include "ci/ciStreams.hpp" -#include "ci/ciTypeFlow.hpp" -#include "memory/allocation.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/llvmValue.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkContext.hpp" -#include "shark/sharkInvariants.hpp" -#include "shark/sharkStack.hpp" - -class SharkTopLevelBlock; -class DeferredZeroCheck; - -class SharkFunction : public SharkTargetInvariants { - friend class SharkStackWithNormalFrame; - - public: - static llvm::Function* build(ciEnv* env, - SharkBuilder* builder, - ciTypeFlow* flow, - const char* name) { - SharkFunction function(env, builder, flow, name); - return function.function(); - } - - private: - SharkFunction(ciEnv* env, - SharkBuilder* builder, - ciTypeFlow* flow, - const char* name) - : SharkTargetInvariants(env, builder, flow) { initialize(name); } - - private: - void initialize(const char* name); - - private: - llvm::Function* _function; - SharkTopLevelBlock** _blocks; - GrowableArray _deferred_zero_checks; - SharkStack* _stack; - - public: - llvm::Function* function() const { - return _function; - } - int block_count() const { - return flow()->block_count(); - } - SharkTopLevelBlock* block(int i) const { - assert(i < block_count(), "should be"); - return _blocks[i]; - } - GrowableArray* deferred_zero_checks() { - return &_deferred_zero_checks; - } - SharkStack* stack() const { - return _stack; - } - - // On-stack replacement - private: - bool is_osr() const { - return flow()->is_osr_flow(); - } - llvm::FunctionType* entry_point_type() const { - if (is_osr()) - return SharkType::osr_entry_point_type(); - else - return SharkType::entry_point_type(); - } - - // Block management - private: - llvm::BasicBlock* _block_insertion_point; - - void set_block_insertion_point(llvm::BasicBlock* block_insertion_point) { - _block_insertion_point = block_insertion_point; - } - llvm::BasicBlock* block_insertion_point() const { - return _block_insertion_point; - } - - public: - llvm::BasicBlock* CreateBlock(const char* name = "") const { - return llvm::BasicBlock::Create( - SharkContext::current(), name, function(), block_insertion_point()); - } - - // Deferred zero checks - public: - void add_deferred_zero_check(SharkTopLevelBlock* block, - SharkValue* value); - - private: - void do_deferred_zero_checks(); -}; - -#endif // SHARE_VM_SHARK_SHARKFUNCTION_HPP diff --git a/src/hotspot/share/shark/sharkInliner.cpp b/src/hotspot/share/shark/sharkInliner.cpp deleted file mode 100644 index 4e56a8382e3..00000000000 --- a/src/hotspot/share/shark/sharkInliner.cpp +++ /dev/null @@ -1,765 +0,0 @@ -/* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "ci/ciField.hpp" -#include "ci/ciMethod.hpp" -#include "ci/ciStreams.hpp" -#include "interpreter/bytecodes.hpp" -#include "memory/allocation.hpp" -#include "memory/resourceArea.hpp" -#include "shark/sharkBlock.hpp" -#include "shark/sharkConstant.hpp" -#include "shark/sharkInliner.hpp" -#include "shark/sharkIntrinsics.hpp" -#include "shark/sharkState.hpp" -#include "shark/sharkValue.hpp" -#include "shark/shark_globals.hpp" - -using namespace llvm; - -class SharkInlineBlock : public SharkBlock { - public: - SharkInlineBlock(ciMethod* target, SharkState* state) - : SharkBlock(state, target), - _outer_state(state), - _entry_state(new SharkState(this)) { - for (int i = target->max_locals() - 1; i >= 0; i--) { - SharkValue *value = NULL; - if (i < target->arg_size()) - value = outer_state()->pop(); - entry_state()->set_local(i, value); - } - } - - private: - SharkState* _outer_state; - SharkState* _entry_state; - - private: - SharkState* outer_state() { - return _outer_state; - } - SharkState* entry_state() { - return _entry_state; - } - - public: - void emit_IR() { - parse_bytecode(0, target()->code_size()); - } - - private: - void do_return(BasicType type) { - if (type != T_VOID) { - SharkValue *result = pop_result(type); - outer_state()->push(result); - if (result->is_two_word()) - outer_state()->push(NULL); - } - } -}; - -class SharkInlinerHelper : public StackObj { - public: - SharkInlinerHelper(ciMethod* target, SharkState* entry_state) - : _target(target), - _entry_state(entry_state), - _iter(target) {} - - private: - ciBytecodeStream _iter; - SharkState* _entry_state; - ciMethod* _target; - - public: - ciBytecodeStream* iter() { - return &_iter; - } - SharkState* entry_state() const { - return _entry_state; - } - ciMethod* target() const { - return _target; - } - - public: - Bytecodes::Code bc() { - return iter()->cur_bc(); - } - int max_locals() const { - return target()->max_locals(); - } - int max_stack() const { - return target()->max_stack(); - } - - // Inlinability check - public: - bool is_inlinable(); - - private: - void initialize_for_check(); - - bool do_getstatic() { - return do_field_access(true, false); - } - bool do_getfield() { - return do_field_access(true, true); - } - bool do_putfield() { - return do_field_access(false, true); - } - bool do_field_access(bool is_get, bool is_field); - - // Local variables for inlinability check - private: - bool* _locals; - - public: - bool* local_addr(int index) const { - assert(index >= 0 && index < max_locals(), "bad local variable index"); - return &_locals[index]; - } - bool local(int index) const { - return *local_addr(index); - } - void set_local(int index, bool value) { - *local_addr(index) = value; - } - - // Expression stack for inlinability check - private: - bool* _stack; - bool* _sp; - - public: - int stack_depth() const { - return _sp - _stack; - } - bool* stack_addr(int slot) const { - assert(slot >= 0 && slot < stack_depth(), "bad stack slot"); - return &_sp[-(slot + 1)]; - } - void push(bool value) { - assert(stack_depth() < max_stack(), "stack overrun"); - *(_sp++) = value; - } - bool pop() { - assert(stack_depth() > 0, "stack underrun"); - return *(--_sp); - } - - // Methods for two-word locals - public: - void push_pair_local(int index) { - push(local(index)); - push(local(index + 1)); - } - void pop_pair_local(int index) { - set_local(index + 1, pop()); - set_local(index, pop()); - } - - // Code generation - public: - void do_inline() { - (new SharkInlineBlock(target(), entry_state()))->emit_IR(); - } -}; - -// Quick checks so we can bail out before doing too much -bool SharkInliner::may_be_inlinable(ciMethod *target) { - // We can't inline native methods - if (target->is_native()) - return false; - - // Not much point inlining abstract ones, and in any - // case we'd need a stack frame to throw the exception - if (target->is_abstract()) - return false; - - // Don't inline anything huge - if (target->code_size() > SharkMaxInlineSize) - return false; - - // Monitors aren't allowed without a frame to put them in - if (target->is_synchronized() || target->has_monitor_bytecodes()) - return false; - - // We don't do control flow - if (target->has_exception_handlers() || target->has_jsrs()) - return false; - - // Don't try to inline constructors, as they must - // eventually call Object. which we can't inline. - // Note that this catches too, but why would - // we be compiling that? - if (target->is_initializer()) - return false; - - // Mustn't inline Object. - // Should be caught by the above, but just in case... - if (target->intrinsic_id() == vmIntrinsics::_Object_init) - return false; - - return true; -} - -// Full-on detailed check, for methods that pass the quick checks -// Inlined methods have no stack frame, so we can't do anything -// that would require one. This means no safepoints (and hence -// no loops) and no VM calls. No VM calls means, amongst other -// things, that no exceptions can be created, which means no null -// checks or divide-by-zero checks are allowed. The lack of null -// checks in particular would eliminate practically everything, -// but we can get around that restriction by relying on the zero- -// check eliminator to strip the checks. To do that, we need to -// walk through the method, tracking which values are and are not -// zero-checked. -bool SharkInlinerHelper::is_inlinable() { - ResourceMark rm; - initialize_for_check(); - - SharkConstant *sc; - bool a, b, c, d; - - iter()->reset_to_bci(0); - while (iter()->next() != ciBytecodeStream::EOBC()) { - switch (bc()) { - case Bytecodes::_nop: - break; - - case Bytecodes::_aconst_null: - push(false); - break; - - case Bytecodes::_iconst_0: - push(false); - break; - case Bytecodes::_iconst_m1: - case Bytecodes::_iconst_1: - case Bytecodes::_iconst_2: - case Bytecodes::_iconst_3: - case Bytecodes::_iconst_4: - case Bytecodes::_iconst_5: - push(true); - break; - - case Bytecodes::_lconst_0: - push(false); - push(false); - break; - case Bytecodes::_lconst_1: - push(true); - push(false); - break; - - case Bytecodes::_fconst_0: - case Bytecodes::_fconst_1: - case Bytecodes::_fconst_2: - push(false); - break; - - case Bytecodes::_dconst_0: - case Bytecodes::_dconst_1: - push(false); - push(false); - break; - - case Bytecodes::_bipush: - push(iter()->get_constant_u1() != 0); - break; - case Bytecodes::_sipush: - push(iter()->get_constant_u2() != 0); - break; - - case Bytecodes::_ldc: - case Bytecodes::_ldc_w: - case Bytecodes::_ldc2_w: - sc = SharkConstant::for_ldc(iter()); - if (!sc->is_loaded()) - return false; - push(sc->is_nonzero()); - if (sc->is_two_word()) - push(false); - break; - - case Bytecodes::_iload_0: - case Bytecodes::_fload_0: - case Bytecodes::_aload_0: - push(local(0)); - break; - case Bytecodes::_lload_0: - case Bytecodes::_dload_0: - push_pair_local(0); - break; - - case Bytecodes::_iload_1: - case Bytecodes::_fload_1: - case Bytecodes::_aload_1: - push(local(1)); - break; - case Bytecodes::_lload_1: - case Bytecodes::_dload_1: - push_pair_local(1); - break; - - case Bytecodes::_iload_2: - case Bytecodes::_fload_2: - case Bytecodes::_aload_2: - push(local(2)); - break; - case Bytecodes::_lload_2: - case Bytecodes::_dload_2: - push_pair_local(2); - break; - - case Bytecodes::_iload_3: - case Bytecodes::_fload_3: - case Bytecodes::_aload_3: - push(local(3)); - break; - case Bytecodes::_lload_3: - case Bytecodes::_dload_3: - push_pair_local(3); - break; - - case Bytecodes::_iload: - case Bytecodes::_fload: - case Bytecodes::_aload: - push(local(iter()->get_index())); - break; - case Bytecodes::_lload: - case Bytecodes::_dload: - push_pair_local(iter()->get_index()); - break; - - case Bytecodes::_istore_0: - case Bytecodes::_fstore_0: - case Bytecodes::_astore_0: - set_local(0, pop()); - break; - case Bytecodes::_lstore_0: - case Bytecodes::_dstore_0: - pop_pair_local(0); - break; - - case Bytecodes::_istore_1: - case Bytecodes::_fstore_1: - case Bytecodes::_astore_1: - set_local(1, pop()); - break; - case Bytecodes::_lstore_1: - case Bytecodes::_dstore_1: - pop_pair_local(1); - break; - - case Bytecodes::_istore_2: - case Bytecodes::_fstore_2: - case Bytecodes::_astore_2: - set_local(2, pop()); - break; - case Bytecodes::_lstore_2: - case Bytecodes::_dstore_2: - pop_pair_local(2); - break; - - case Bytecodes::_istore_3: - case Bytecodes::_fstore_3: - case Bytecodes::_astore_3: - set_local(3, pop()); - break; - case Bytecodes::_lstore_3: - case Bytecodes::_dstore_3: - pop_pair_local(3); - break; - - case Bytecodes::_istore: - case Bytecodes::_fstore: - case Bytecodes::_astore: - set_local(iter()->get_index(), pop()); - break; - case Bytecodes::_lstore: - case Bytecodes::_dstore: - pop_pair_local(iter()->get_index()); - break; - - case Bytecodes::_pop: - pop(); - break; - case Bytecodes::_pop2: - pop(); - pop(); - break; - case Bytecodes::_swap: - a = pop(); - b = pop(); - push(a); - push(b); - break; - case Bytecodes::_dup: - a = pop(); - push(a); - push(a); - break; - case Bytecodes::_dup_x1: - a = pop(); - b = pop(); - push(a); - push(b); - push(a); - break; - case Bytecodes::_dup_x2: - a = pop(); - b = pop(); - c = pop(); - push(a); - push(c); - push(b); - push(a); - break; - case Bytecodes::_dup2: - a = pop(); - b = pop(); - push(b); - push(a); - push(b); - push(a); - break; - case Bytecodes::_dup2_x1: - a = pop(); - b = pop(); - c = pop(); - push(b); - push(a); - push(c); - push(b); - push(a); - break; - case Bytecodes::_dup2_x2: - a = pop(); - b = pop(); - c = pop(); - d = pop(); - push(b); - push(a); - push(d); - push(c); - push(b); - push(a); - break; - - case Bytecodes::_getfield: - if (!do_getfield()) - return false; - break; - case Bytecodes::_getstatic: - if (!do_getstatic()) - return false; - break; - case Bytecodes::_putfield: - if (!do_putfield()) - return false; - break; - - case Bytecodes::_iadd: - case Bytecodes::_isub: - case Bytecodes::_imul: - case Bytecodes::_iand: - case Bytecodes::_ixor: - case Bytecodes::_ishl: - case Bytecodes::_ishr: - case Bytecodes::_iushr: - pop(); - pop(); - push(false); - break; - case Bytecodes::_ior: - a = pop(); - b = pop(); - push(a && b); - break; - case Bytecodes::_idiv: - case Bytecodes::_irem: - if (!pop()) - return false; - pop(); - push(false); - break; - case Bytecodes::_ineg: - break; - - case Bytecodes::_ladd: - case Bytecodes::_lsub: - case Bytecodes::_lmul: - case Bytecodes::_land: - case Bytecodes::_lxor: - pop(); - pop(); - pop(); - pop(); - push(false); - push(false); - break; - case Bytecodes::_lor: - a = pop(); - b = pop(); - push(a && b); - break; - case Bytecodes::_ldiv: - case Bytecodes::_lrem: - pop(); - if (!pop()) - return false; - pop(); - pop(); - push(false); - push(false); - break; - case Bytecodes::_lneg: - break; - case Bytecodes::_lshl: - case Bytecodes::_lshr: - case Bytecodes::_lushr: - pop(); - pop(); - pop(); - push(false); - push(false); - break; - - case Bytecodes::_fadd: - case Bytecodes::_fsub: - case Bytecodes::_fmul: - case Bytecodes::_fdiv: - case Bytecodes::_frem: - pop(); - pop(); - push(false); - break; - case Bytecodes::_fneg: - break; - - case Bytecodes::_dadd: - case Bytecodes::_dsub: - case Bytecodes::_dmul: - case Bytecodes::_ddiv: - case Bytecodes::_drem: - pop(); - pop(); - pop(); - pop(); - push(false); - push(false); - break; - case Bytecodes::_dneg: - break; - - case Bytecodes::_iinc: - set_local(iter()->get_index(), false); - break; - - case Bytecodes::_lcmp: - pop(); - pop(); - pop(); - pop(); - push(false); - break; - - case Bytecodes::_fcmpl: - case Bytecodes::_fcmpg: - pop(); - pop(); - push(false); - break; - - case Bytecodes::_dcmpl: - case Bytecodes::_dcmpg: - pop(); - pop(); - pop(); - pop(); - push(false); - break; - - case Bytecodes::_i2l: - push(false); - break; - case Bytecodes::_i2f: - pop(); - push(false); - break; - case Bytecodes::_i2d: - pop(); - push(false); - push(false); - break; - - case Bytecodes::_l2i: - case Bytecodes::_l2f: - pop(); - pop(); - push(false); - break; - case Bytecodes::_l2d: - pop(); - pop(); - push(false); - push(false); - break; - - case Bytecodes::_f2i: - pop(); - push(false); - break; - case Bytecodes::_f2l: - case Bytecodes::_f2d: - pop(); - push(false); - push(false); - break; - - case Bytecodes::_d2i: - case Bytecodes::_d2f: - pop(); - pop(); - push(false); - break; - case Bytecodes::_d2l: - pop(); - pop(); - push(false); - push(false); - break; - - case Bytecodes::_i2b: - case Bytecodes::_i2c: - case Bytecodes::_i2s: - pop(); - push(false); - break; - - case Bytecodes::_return: - case Bytecodes::_ireturn: - case Bytecodes::_lreturn: - case Bytecodes::_freturn: - case Bytecodes::_dreturn: - case Bytecodes::_areturn: - break; - - default: - return false; - } - } - - return true; -} - -void SharkInlinerHelper::initialize_for_check() { - _locals = NEW_RESOURCE_ARRAY(bool, max_locals()); - _stack = NEW_RESOURCE_ARRAY(bool, max_stack()); - - memset(_locals, 0, max_locals() * sizeof(bool)); - for (int i = 0; i < target()->arg_size(); i++) { - SharkValue *arg = entry_state()->stack(target()->arg_size() - 1 - i); - if (arg && arg->zero_checked()) - set_local(i, true); - } - - _sp = _stack; -} - -bool SharkInlinerHelper::do_field_access(bool is_get, bool is_field) { - assert(is_get || is_field, "can't inline putstatic"); - - // If the holder isn't linked then there isn't a lot we can do - if (!target()->holder()->is_linked()) - return false; - - // Get the field - bool will_link; - ciField *field = iter()->get_field(will_link); - if (!will_link) - return false; - - // If the field is mismatched then an exception needs throwing - if (is_field == field->is_static()) - return false; - - // Pop the value off the stack if necessary - if (!is_get) { - pop(); - if (field->type()->is_two_word()) - pop(); - } - - // Pop and null-check the receiver if necessary - if (is_field) { - if (!pop()) - return false; - } - - // Push the result if necessary - if (is_get) { - bool result_pushed = false; - if (field->is_constant() && field->is_static()) { - SharkConstant *sc = SharkConstant::for_field(iter()); - if (sc->is_loaded()) { - push(sc->is_nonzero()); - result_pushed = true; - } - } - - if (!result_pushed) - push(false); - - if (field->type()->is_two_word()) - push(false); - } - - return true; -} - -bool SharkInliner::attempt_inline(ciMethod *target, SharkState *state) { - if (!Inline) { - return false; - } - - if (SharkIntrinsics::is_intrinsic(target)) { - SharkIntrinsics::inline_intrinsic(target, state); - return true; - } - - if (may_be_inlinable(target)) { - SharkInlinerHelper inliner(target, state); - if (inliner.is_inlinable()) { - inliner.do_inline(); - return true; - } - } - return false; -} diff --git a/src/hotspot/share/shark/sharkIntrinsics.cpp b/src/hotspot/share/shark/sharkIntrinsics.cpp deleted file mode 100644 index 15b6679bf4e..00000000000 --- a/src/hotspot/share/shark/sharkIntrinsics.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "ci/ciMethod.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkIntrinsics.hpp" -#include "shark/sharkState.hpp" -#include "shark/sharkValue.hpp" -#include "shark/shark_globals.hpp" - -using namespace llvm; - -bool SharkIntrinsics::is_intrinsic(ciMethod *target) { - switch (target->intrinsic_id()) { - case vmIntrinsics::_none: - return false; - - // java.lang.Math - case vmIntrinsics::_min: - case vmIntrinsics::_max: - case vmIntrinsics::_dabs: - case vmIntrinsics::_dsin: - case vmIntrinsics::_dcos: - case vmIntrinsics::_dtan: - case vmIntrinsics::_datan2: - case vmIntrinsics::_dsqrt: - case vmIntrinsics::_dlog: - case vmIntrinsics::_dlog10: - case vmIntrinsics::_dpow: - case vmIntrinsics::_dexp: - return true; - - // java.lang.Object - case vmIntrinsics::_getClass: - return true; - - // java.lang.System - case vmIntrinsics::_currentTimeMillis: - return true; - - // java.lang.Thread - case vmIntrinsics::_currentThread: - return true; - - // Unsafe - case vmIntrinsics::_compareAndSetInt: - return true; - - default: - if (SharkPerformanceWarnings) { - warning( - "unhandled intrinsic vmIntrinsic::%s", - vmIntrinsics::name_at(target->intrinsic_id())); - } - } - return false; -} - -void SharkIntrinsics::inline_intrinsic(ciMethod *target, SharkState *state) { - SharkIntrinsics intrinsic(state, target); - intrinsic.do_intrinsic(); -} - -void SharkIntrinsics::do_intrinsic() { - switch (target()->intrinsic_id()) { - // java.lang.Math - case vmIntrinsics::_min: - do_Math_minmax(llvm::ICmpInst::ICMP_SLE); - break; - case vmIntrinsics::_max: - do_Math_minmax(llvm::ICmpInst::ICMP_SGE); - break; - case vmIntrinsics::_dabs: - do_Math_1to1(builder()->fabs()); - break; - case vmIntrinsics::_dsin: - do_Math_1to1(builder()->sin()); - break; - case vmIntrinsics::_dcos: - do_Math_1to1(builder()->cos()); - break; - case vmIntrinsics::_dtan: - do_Math_1to1(builder()->tan()); - break; - case vmIntrinsics::_datan2: - do_Math_2to1(builder()->atan2()); - break; - case vmIntrinsics::_dsqrt: - do_Math_1to1(builder()->sqrt()); - break; - case vmIntrinsics::_dlog: - do_Math_1to1(builder()->log()); - break; - case vmIntrinsics::_dlog10: - do_Math_1to1(builder()->log10()); - break; - case vmIntrinsics::_dpow: - do_Math_2to1(builder()->pow()); - break; - case vmIntrinsics::_dexp: - do_Math_1to1(builder()->exp()); - break; - - // java.lang.Object - case vmIntrinsics::_getClass: - do_Object_getClass(); - break; - - // java.lang.System - case vmIntrinsics::_currentTimeMillis: - do_System_currentTimeMillis(); - break; - - // java.lang.Thread - case vmIntrinsics::_currentThread: - do_Thread_currentThread(); - break; - - // Unsafe - case vmIntrinsics::_compareAndSetInt: - do_Unsafe_compareAndSetInt(); - break; - - default: - ShouldNotReachHere(); - } -} - -void SharkIntrinsics::do_Math_minmax(ICmpInst::Predicate p) { - // Pop the arguments - SharkValue *sb = state()->pop(); - SharkValue *sa = state()->pop(); - Value *a = sa->jint_value(); - Value *b = sb->jint_value(); - - // Perform the test - BasicBlock *ip = builder()->GetBlockInsertionPoint(); - BasicBlock *return_a = builder()->CreateBlock(ip, "return_a"); - BasicBlock *return_b = builder()->CreateBlock(ip, "return_b"); - BasicBlock *done = builder()->CreateBlock(ip, "done"); - - builder()->CreateCondBr(builder()->CreateICmp(p, a, b), return_a, return_b); - - builder()->SetInsertPoint(return_a); - builder()->CreateBr(done); - - builder()->SetInsertPoint(return_b); - builder()->CreateBr(done); - - builder()->SetInsertPoint(done); - PHINode *phi = builder()->CreatePHI(a->getType(), 0, "result"); - phi->addIncoming(a, return_a); - phi->addIncoming(b, return_b); - - // Push the result - state()->push( - SharkValue::create_jint( - phi, - sa->zero_checked() && sb->zero_checked())); -} - -void SharkIntrinsics::do_Math_1to1(Value *function) { - SharkValue *empty = state()->pop(); - assert(empty == NULL, "should be"); - state()->push( - SharkValue::create_jdouble( - builder()->CreateCall( - function, state()->pop()->jdouble_value()))); - state()->push(NULL); -} - -void SharkIntrinsics::do_Math_2to1(Value *function) { - SharkValue *empty = state()->pop(); - assert(empty == NULL, "should be"); - Value *y = state()->pop()->jdouble_value(); - empty = state()->pop(); - assert(empty == NULL, "should be"); - Value *x = state()->pop()->jdouble_value(); - - state()->push( - SharkValue::create_jdouble( - builder()->CreateCall2(function, x, y))); - state()->push(NULL); -} - -void SharkIntrinsics::do_Object_getClass() { - Value *klass = builder()->CreateValueOfStructEntry( - state()->pop()->jobject_value(), - in_ByteSize(oopDesc::klass_offset_in_bytes()), - SharkType::klass_type(), - "klass"); - - state()->push( - SharkValue::create_jobject( - builder()->CreateValueOfStructEntry( - klass, - Klass::java_mirror_offset(), - SharkType::oop_type(), - "java_mirror"), - true)); -} - -void SharkIntrinsics::do_System_currentTimeMillis() { - state()->push( - SharkValue::create_jlong( - builder()->CreateCall(builder()->current_time_millis()), - false)); - state()->push(NULL); -} - -void SharkIntrinsics::do_Thread_currentThread() { - state()->push( - SharkValue::create_jobject( - builder()->CreateValueOfStructEntry( - thread(), JavaThread::threadObj_offset(), - SharkType::oop_type(), - "threadObj"), - true)); -} - -void SharkIntrinsics::do_Unsafe_compareAndSetInt() { - // Pop the arguments - Value *x = state()->pop()->jint_value(); - Value *e = state()->pop()->jint_value(); - SharkValue *empty = state()->pop(); - assert(empty == NULL, "should be"); - Value *offset = state()->pop()->jlong_value(); - Value *object = state()->pop()->jobject_value(); - Value *unsafe = state()->pop()->jobject_value(); - - // Convert the offset - offset = builder()->CreateCall( - builder()->unsafe_field_offset_to_byte_offset(), - offset); - - // Locate the field - Value *addr = builder()->CreateIntToPtr( - builder()->CreateAdd( - builder()->CreatePtrToInt(object, SharkType::intptr_type()), - builder()->CreateIntCast(offset, SharkType::intptr_type(), true)), - PointerType::getUnqual(SharkType::jint_type()), - "addr"); - - // Perform the operation - Value *result = builder()->CreateAtomicCmpXchg(addr, e, x, llvm::SequentiallyConsistent); - // Push the result - state()->push( - SharkValue::create_jint( - builder()->CreateIntCast( - builder()->CreateICmpEQ(result, e), SharkType::jint_type(), true), - false)); -} diff --git a/src/hotspot/share/shark/sharkIntrinsics.hpp b/src/hotspot/share/shark/sharkIntrinsics.hpp deleted file mode 100644 index 8a5d60f17b9..00000000000 --- a/src/hotspot/share/shark/sharkIntrinsics.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKINTRINSICS_HPP -#define SHARE_VM_SHARK_SHARKINTRINSICS_HPP - -#include "ci/ciMethod.hpp" -#include "memory/allocation.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkState.hpp" - -class SharkIntrinsics : public SharkTargetInvariants { - public: - static bool is_intrinsic(ciMethod* target); - static void inline_intrinsic(ciMethod* target, SharkState* state); - - private: - SharkIntrinsics(SharkState* state, ciMethod* target) - : SharkTargetInvariants(state, target), _state(state) {} - - private: - SharkState* _state; - - private: - SharkState* state() const { - return _state; - } - - private: - void do_intrinsic(); - - private: - void do_Math_minmax(llvm::ICmpInst::Predicate p); - void do_Math_1to1(llvm::Value* function); - void do_Math_2to1(llvm::Value* function); - void do_Object_getClass(); - void do_System_currentTimeMillis(); - void do_Thread_currentThread(); - void do_Unsafe_compareAndSetInt(); -}; - -#endif // SHARE_VM_SHARK_SHARKINTRINSICS_HPP diff --git a/src/hotspot/share/shark/sharkInvariants.hpp b/src/hotspot/share/shark/sharkInvariants.hpp deleted file mode 100644 index 8206c473225..00000000000 --- a/src/hotspot/share/shark/sharkInvariants.hpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKINVARIANTS_HPP -#define SHARE_VM_SHARK_SHARKINVARIANTS_HPP - -#include "ci/ciEnv.hpp" -#include "ci/ciInstanceKlass.hpp" -#include "ci/ciMethod.hpp" -#include "ci/ciTypeFlow.hpp" -#include "code/debugInfoRec.hpp" -#include "code/dependencies.hpp" -#include "memory/allocation.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkBuilder.hpp" - -// Base classes used to track various values through the compilation. -// SharkCompileInvariants is used to track values which remain the -// same for the top-level method and any inlined methods it may have -// (ie for the whole compilation). SharkTargetInvariants is used to -// track values which differ between methods. - -class SharkCompileInvariants : public ResourceObj { - protected: - SharkCompileInvariants(ciEnv* env, SharkBuilder* builder) - : _env(env), - _builder(builder), - _thread(NULL) {} - - SharkCompileInvariants(const SharkCompileInvariants* parent) - : _env(parent->_env), - _builder(parent->_builder), - _thread(parent->_thread) {} - - private: - ciEnv* _env; - SharkBuilder* _builder; - llvm::Value* _thread; - - // Top-level broker for HotSpot's Compiler Interface. - // - // Its main purpose is to allow the various CI classes to access - // oops in the VM without having to worry about safepointing. In - // addition to this it acts as a holder for various recorders and - // memory allocators. - // - // Accessing this directly is kind of ugly, so it's private. Add - // new accessors below if you need something from it. - protected: - ciEnv* env() const { - assert(_env != NULL, "env not available"); - return _env; - } - - // The SharkBuilder that is used to build LLVM IR. - protected: - SharkBuilder* builder() const { - return _builder; - } - - // Pointer to this thread's JavaThread object. This is not - // available until a short way into SharkFunction creation - // so a setter is required. Assertions are used to enforce - // invariance. - protected: - llvm::Value* thread() const { - assert(_thread != NULL, "thread not available"); - return _thread; - } - void set_thread(llvm::Value* thread) { - assert(_thread == NULL, "thread already set"); - _thread = thread; - } - - // Objects that handle various aspects of the compilation. - protected: - DebugInformationRecorder* debug_info() const { - return env()->debug_info(); - } - SharkCodeBuffer* code_buffer() const { - return builder()->code_buffer(); - } - - public: - Dependencies* dependencies() const { - return env()->dependencies(); - } - - // Commonly used classes - protected: - ciInstanceKlass* java_lang_Object_klass() const { - return env()->Object_klass(); - } - ciInstanceKlass* java_lang_Throwable_klass() const { - return env()->Throwable_klass(); - } -}; - -class SharkTargetInvariants : public SharkCompileInvariants { - protected: - SharkTargetInvariants(ciEnv* env, SharkBuilder* builder, ciTypeFlow* flow) - : SharkCompileInvariants(env, builder), - _target(flow->method()), - _flow(flow), - _max_monitors(count_monitors()) {} - - SharkTargetInvariants(const SharkCompileInvariants* parent, ciMethod* target) - : SharkCompileInvariants(parent), - _target(target), - _flow(NULL), - _max_monitors(count_monitors()) {} - - SharkTargetInvariants(const SharkTargetInvariants* parent) - : SharkCompileInvariants(parent), - _target(parent->_target), - _flow(parent->_flow), - _max_monitors(parent->_max_monitors) {} - - private: - int count_monitors(); - - private: - ciMethod* _target; - ciTypeFlow* _flow; - int _max_monitors; - - // The method being compiled. - protected: - ciMethod* target() const { - return _target; - } - - // Typeflow analysis of the method being compiled. - protected: - ciTypeFlow* flow() const { - assert(_flow != NULL, "typeflow not available"); - return _flow; - } - - // Properties of the method. - protected: - int max_locals() const { - return target()->max_locals(); - } - int max_stack() const { - return target()->max_stack(); - } - int max_monitors() const { - return _max_monitors; - } - int arg_size() const { - return target()->arg_size(); - } - bool is_static() const { - return target()->is_static(); - } - bool is_synchronized() const { - return target()->is_synchronized(); - } -}; - -#endif // SHARE_VM_SHARK_SHARKINVARIANTS_HPP diff --git a/src/hotspot/share/shark/sharkMemoryManager.cpp b/src/hotspot/share/shark/sharkMemoryManager.cpp deleted file mode 100644 index d986ae8868b..00000000000 --- a/src/hotspot/share/shark/sharkMemoryManager.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkEntry.hpp" -#include "shark/sharkMemoryManager.hpp" - -using namespace llvm; - -void SharkMemoryManager::AllocateGOT() { - mm()->AllocateGOT(); -} - -unsigned char* SharkMemoryManager::getGOTBase() const { - return mm()->getGOTBase(); -} - -unsigned char* SharkMemoryManager::allocateStub(const GlobalValue* F, - unsigned StubSize, - unsigned Alignment) { - return mm()->allocateStub(F, StubSize, Alignment); -} - -unsigned char* SharkMemoryManager::startFunctionBody(const Function* F, - uintptr_t& ActualSize) { - return mm()->startFunctionBody(F, ActualSize); -} - -void SharkMemoryManager::endFunctionBody(const Function* F, - unsigned char* FunctionStart, - unsigned char* FunctionEnd) { - mm()->endFunctionBody(F, FunctionStart, FunctionEnd); - - SharkEntry *entry = get_entry_for_function(F); - if (entry != NULL) - entry->set_code_limit(FunctionEnd); -} - -void SharkMemoryManager::setMemoryWritable() { - mm()->setMemoryWritable(); -} - -void SharkMemoryManager::setMemoryExecutable() { - mm()->setMemoryExecutable(); -} - -void SharkMemoryManager::deallocateFunctionBody(void *ptr) { - mm()->deallocateFunctionBody(ptr); -} - -uint8_t* SharkMemoryManager::allocateGlobal(uintptr_t Size, - unsigned int Alignment) { - return mm()->allocateGlobal(Size, Alignment); -} - -void* SharkMemoryManager::getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure) { - return mm()->getPointerToNamedFunction(Name, AbortOnFailure); -} - -void SharkMemoryManager::setPoisonMemory(bool poison) { - mm()->setPoisonMemory(poison); -} - -unsigned char *SharkMemoryManager::allocateSpace(intptr_t Size, - unsigned int Alignment) { - return mm()->allocateSpace(Size, Alignment); -} - -#if SHARK_LLVM_VERSION <= 32 - -uint8_t* SharkMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) { - return mm()->allocateCodeSection(Size, Alignment, SectionID); -} - -uint8_t* SharkMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) { - return mm()->allocateDataSection(Size, Alignment, SectionID); -} - -void SharkMemoryManager::deallocateExceptionTable(void *ptr) { - mm()->deallocateExceptionTable(ptr); -} - -unsigned char* SharkMemoryManager::startExceptionTable(const Function* F, - uintptr_t& ActualSize) { - return mm()->startExceptionTable(F, ActualSize); -} - -void SharkMemoryManager::endExceptionTable(const Function* F, - unsigned char* TableStart, - unsigned char* TableEnd, - unsigned char* FrameRegister) { - mm()->endExceptionTable(F, TableStart, TableEnd, FrameRegister); -} - -#else - -uint8_t *SharkMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName) { - return mm()->allocateCodeSection(Size, Alignment, SectionID, SectionName); -} - -uint8_t* SharkMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName, bool IsReadOnly) { - return mm()->allocateDataSection(Size, Alignment, SectionID, SectionName, IsReadOnly); -} - -bool SharkMemoryManager::finalizeMemory(std::string *ErrMsg) { - return mm()->finalizeMemory(ErrMsg); -} - -#endif diff --git a/src/hotspot/share/shark/sharkMemoryManager.hpp b/src/hotspot/share/shark/sharkMemoryManager.hpp deleted file mode 100644 index 7a5ad7b3e1c..00000000000 --- a/src/hotspot/share/shark/sharkMemoryManager.hpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKMEMORYMANAGER_HPP -#define SHARE_VM_SHARK_SHARKMEMORYMANAGER_HPP - -#include "shark/llvmHeaders.hpp" -#include "shark/sharkEntry.hpp" - -// SharkMemoryManager wraps the LLVM JIT Memory Manager. We could use -// this to run our own memory allocation policies, but for now all we -// use it for is figuring out where the resulting native code ended up. - -class SharkMemoryManager : public llvm::JITMemoryManager { - public: - SharkMemoryManager() - : _mm(llvm::JITMemoryManager::CreateDefaultMemManager()) {} - - private: - llvm::JITMemoryManager* _mm; - - private: - llvm::JITMemoryManager* mm() const { - return _mm; - } - - private: - std::map _entry_map; - - public: - void set_entry_for_function(const llvm::Function* function, - SharkEntry* entry) { - _entry_map[function] = entry; - } - SharkEntry* get_entry_for_function(const llvm::Function* function) { - return _entry_map[function]; - } - - public: - void AllocateGOT(); - unsigned char* getGOTBase() const; - unsigned char* allocateStub(const llvm::GlobalValue* F, - unsigned StubSize, - unsigned Alignment); - unsigned char* startFunctionBody(const llvm::Function* F, - uintptr_t& ActualSize); - void endFunctionBody(const llvm::Function* F, - unsigned char* FunctionStart, - unsigned char* FunctionEnd); - - void *getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure = true); - void setPoisonMemory(bool); - uint8_t* allocateGlobal(uintptr_t, unsigned int); - void setMemoryWritable(); - void setMemoryExecutable(); - void deallocateFunctionBody(void *ptr); - unsigned char *allocateSpace(intptr_t Size, - unsigned int Alignment); - -#if SHARK_LLVM_VERSION <= 32 -uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID); -uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID); -unsigned char* startExceptionTable(const llvm::Function* F, - uintptr_t& ActualSize); -void deallocateExceptionTable(void *ptr); -void endExceptionTable(const llvm::Function* F, - unsigned char* TableStart, - unsigned char* TableEnd, - unsigned char* FrameRegister); -#else -uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, llvm::StringRef SectionName); -uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, llvm::StringRef SectionName, bool IsReadOnly); -bool finalizeMemory(std::string *ErrMsg = 0); -#endif - -}; - -#endif // SHARE_VM_SHARK_SHARKMEMORYMANAGER_HPP diff --git a/src/hotspot/share/shark/sharkNativeWrapper.cpp b/src/hotspot/share/shark/sharkNativeWrapper.cpp deleted file mode 100644 index b9ac6a3ebf5..00000000000 --- a/src/hotspot/share/shark/sharkNativeWrapper.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009, 2010 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkNativeWrapper.hpp" -#include "shark/sharkType.hpp" - -using namespace llvm; - -void SharkNativeWrapper::initialize(const char *name) { - // Create the function - _function = Function::Create( - SharkType::entry_point_type(), - GlobalVariable::InternalLinkage, - name); - - // Get our arguments - Function::arg_iterator ai = function()->arg_begin(); - Argument *method = ai++; - method->setName("method"); - Argument *base_pc = ai++; - base_pc->setName("base_pc"); - code_buffer()->set_base_pc(base_pc); - Argument *thread = ai++; - thread->setName("thread"); - set_thread(thread); - - // Create and push our stack frame - builder()->SetInsertPoint(CreateBlock()); - _stack = SharkStack::CreateBuildAndPushFrame(this, method); - NOT_PRODUCT(method = NULL); - - // Create the oopmap. We use the one oopmap for every call site in - // the wrapper, which results in the odd mild inefficiency but is a - // damn sight easier to code. - OopMap *oopmap = new OopMap( - SharkStack::oopmap_slot_munge(stack()->oopmap_frame_size()), - SharkStack::oopmap_slot_munge(arg_size())); - - // Set up the oop_tmp slot if required: - // - For static methods we use it to handlize the class argument - // for the call, and to protect the same during slow path locks - // (if synchronized). - // - For methods returning oops, we use it to protect the return - // value across safepoints or slow path unlocking. - if (is_static() || is_returning_oop()) { - _oop_tmp_slot = stack()->slot_addr( - stack()->oop_tmp_slot_offset(), - SharkType::oop_type(), - "oop_tmp_slot"); - - oopmap->set_oop(SharkStack::slot2reg(stack()->oop_tmp_slot_offset())); - } - - // Set up the monitor slot, for synchronized methods - if (is_synchronized()) { - Unimplemented(); - _lock_slot_offset = 23; - } - - // Start building the argument list - std::vector param_types; - std::vector param_values; - PointerType *box_type = PointerType::getUnqual(SharkType::oop_type()); - - // First argument is the JNIEnv - param_types.push_back(SharkType::jniEnv_type()); - param_values.push_back( - builder()->CreateAddressOfStructEntry( - thread, - JavaThread::jni_environment_offset(), - SharkType::jniEnv_type(), - "jni_environment")); - - // For static methods, the second argument is the class - if (is_static()) { - builder()->CreateStore( - builder()->CreateInlineOop( - JNIHandles::make_local( - target()->method_holder()->java_mirror())), - oop_tmp_slot()); - - param_types.push_back(box_type); - param_values.push_back(oop_tmp_slot()); - - _receiver_slot_offset = stack()->oop_tmp_slot_offset(); - } - else if (is_returning_oop()) { - // The oop_tmp slot is registered in the oopmap, - // so we need to clear it. This is one of the - // mild inefficiencies I mentioned earlier. - builder()->CreateStore(LLVMValue::null(), oop_tmp_slot()); - } - - // Parse the arguments - for (int i = 0; i < arg_size(); i++) { - int slot_offset = stack()->locals_slots_offset() + arg_size() - 1 - i; - int adjusted_offset = slot_offset; - BasicBlock *null, *not_null, *merge; - Value *box; - PHINode *phi; - - switch (arg_type(i)) { - case T_VOID: - break; - - case T_OBJECT: - case T_ARRAY: - null = CreateBlock("null"); - not_null = CreateBlock("not_null"); - merge = CreateBlock("merge"); - - box = stack()->slot_addr(slot_offset, SharkType::oop_type()); - builder()->CreateCondBr( - builder()->CreateICmp( - ICmpInst::ICMP_EQ, - builder()->CreateLoad(box), - LLVMValue::null()), - null, not_null); - - builder()->SetInsertPoint(null); - builder()->CreateBr(merge); - - builder()->SetInsertPoint(not_null); - builder()->CreateBr(merge); - - builder()->SetInsertPoint(merge); - phi = builder()->CreatePHI(box_type, 0, "boxed_object"); - phi->addIncoming(ConstantPointerNull::get(box_type), null); - phi->addIncoming(box, not_null); - box = phi; - - param_types.push_back(box_type); - param_values.push_back(box); - - oopmap->set_oop(SharkStack::slot2reg(slot_offset)); - - if (i == 0 && !is_static()) - _receiver_slot_offset = slot_offset; - - break; - - case T_LONG: - case T_DOUBLE: - adjusted_offset--; - // fall through - - default: - Type *param_type = SharkType::to_stackType(arg_type(i)); - - param_types.push_back(param_type); - param_values.push_back( - builder()->CreateLoad(stack()->slot_addr(adjusted_offset, param_type))); - } - } - - // The oopmap is now complete, and everything is written - // into the frame except the PC. - int pc_offset = code_buffer()->create_unique_offset(); - - _oop_maps = new OopMapSet(); - oop_maps()->add_gc_map(pc_offset, oopmap); - - builder()->CreateStore( - builder()->code_buffer_address(pc_offset), - stack()->slot_addr(stack()->pc_slot_offset())); - - // Set up the Java frame anchor - stack()->CreateSetLastJavaFrame(); - - // Lock if necessary - if (is_synchronized()) - Unimplemented(); - - // Change the thread state to _thread_in_native - CreateSetThreadState(_thread_in_native); - - // Make the call - BasicType result_type = target()->result_type(); - Type* return_type; - if (result_type == T_VOID) - return_type = SharkType::void_type(); - else if (is_returning_oop()) - return_type = box_type; - else - return_type = SharkType::to_arrayType(result_type); - Value* native_function = builder()->CreateIntToPtr( - LLVMValue::intptr_constant((intptr_t) target()->native_function()), - PointerType::getUnqual( - FunctionType::get(return_type, param_types, false))); - Value *result = builder()->CreateCall( - native_function, llvm::makeArrayRef(param_values)); - - // Start the transition back to _thread_in_Java - CreateSetThreadState(_thread_in_native_trans); - - // Make sure new state is visible in the GC thread - if (os::is_MP()) { - if (UseMembar) - builder()->CreateFence(llvm::SequentiallyConsistent, llvm::CrossThread); - else - CreateWriteMemorySerializePage(); - } - - // Handle safepoint operations, pending suspend requests, - // and pending asynchronous exceptions. - BasicBlock *check_thread = CreateBlock("check_thread"); - BasicBlock *do_safepoint = CreateBlock("do_safepoint"); - BasicBlock *safepointed = CreateBlock("safepointed"); - - Value *global_state = builder()->CreateLoad( - builder()->CreateIntToPtr( - LLVMValue::intptr_constant( - (intptr_t) SafepointSynchronize::address_of_state()), - PointerType::getUnqual(SharkType::jint_type())), - "global_state"); - - builder()->CreateCondBr( - builder()->CreateICmpNE( - global_state, - LLVMValue::jint_constant(SafepointSynchronize::_not_synchronized)), - do_safepoint, check_thread); - - builder()->SetInsertPoint(check_thread); - Value *thread_state = builder()->CreateValueOfStructEntry( - thread, - JavaThread::suspend_flags_offset(), - SharkType::jint_type(), - "thread_state"); - - builder()->CreateCondBr( - builder()->CreateICmpNE( - thread_state, - LLVMValue::jint_constant(0)), - do_safepoint, safepointed); - - builder()->SetInsertPoint(do_safepoint); - builder()->CreateCall( - builder()->check_special_condition_for_native_trans(), thread); - builder()->CreateBr(safepointed); - - // Finally we can change the thread state to _thread_in_Java - builder()->SetInsertPoint(safepointed); - CreateSetThreadState(_thread_in_Java); - - // Clear the frame anchor - stack()->CreateResetLastJavaFrame(); - - // If there is a pending exception then we can just unwind and - // return. It seems totally wrong that unlocking is skipped here - // but apparently the template interpreter does this so we do too. - BasicBlock *exception = CreateBlock("exception"); - BasicBlock *no_exception = CreateBlock("no_exception"); - - builder()->CreateCondBr( - builder()->CreateICmpEQ( - CreateLoadPendingException(), - LLVMValue::null()), - no_exception, exception); - - builder()->SetInsertPoint(exception); - CreateResetHandleBlock(); - stack()->CreatePopFrame(0); - builder()->CreateRet(LLVMValue::jint_constant(0)); - - builder()->SetInsertPoint(no_exception); - - // If the result was an oop then unbox it before - // releasing the handle it might be protected by - if (is_returning_oop()) { - BasicBlock *null = builder()->GetInsertBlock(); - BasicBlock *not_null = CreateBlock("not_null"); - BasicBlock *merge = CreateBlock("merge"); - - builder()->CreateCondBr( - builder()->CreateICmpNE(result, ConstantPointerNull::get(box_type)), - not_null, merge); - - builder()->SetInsertPoint(not_null); -#error Needs to be updated for tagged jweak; see JNIHandles. - Value *unboxed_result = builder()->CreateLoad(result); - builder()->CreateBr(merge); - - builder()->SetInsertPoint(merge); - PHINode *phi = builder()->CreatePHI(SharkType::oop_type(), 0, "result"); - phi->addIncoming(LLVMValue::null(), null); - phi->addIncoming(unboxed_result, not_null); - result = phi; - } - - // Reset handle block - CreateResetHandleBlock(); - - // Unlock if necessary. - if (is_synchronized()) - Unimplemented(); - - // Unwind and return - Value *result_addr = stack()->CreatePopFrame(type2size[result_type]); - if (result_type != T_VOID) { - bool needs_cast = false; - bool is_signed = false; - switch (result_type) { - case T_BOOLEAN: - result = builder()->CreateICmpNE(result, LLVMValue::jbyte_constant(0)); - needs_cast = true; - break; - - case T_CHAR: - needs_cast = true; - break; - - case T_BYTE: - case T_SHORT: - needs_cast = true; - is_signed = true; - break; - } - if (needs_cast) { - result = builder()->CreateIntCast( - result, SharkType::to_stackType(result_type), is_signed); - } - - builder()->CreateStore( - result, - builder()->CreateIntToPtr( - result_addr, - PointerType::getUnqual(SharkType::to_stackType(result_type)))); - } - builder()->CreateRet(LLVMValue::jint_constant(0)); -} diff --git a/src/hotspot/share/shark/sharkNativeWrapper.hpp b/src/hotspot/share/shark/sharkNativeWrapper.hpp deleted file mode 100644 index 3d4eddd13fb..00000000000 --- a/src/hotspot/share/shark/sharkNativeWrapper.hpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKNATIVEWRAPPER_HPP -#define SHARE_VM_SHARK_SHARKNATIVEWRAPPER_HPP - -#include "runtime/handles.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkContext.hpp" -#include "shark/sharkInvariants.hpp" -#include "shark/sharkStack.hpp" - -class SharkNativeWrapper : public SharkCompileInvariants { - friend class SharkStackWithNativeFrame; - - public: - static SharkNativeWrapper* build(SharkBuilder* builder, - methodHandle target, - const char* name, - BasicType* arg_types, - BasicType return_type) { - return new SharkNativeWrapper(builder, - target, - name, - arg_types, - return_type); - } - - private: - SharkNativeWrapper(SharkBuilder* builder, - methodHandle target, - const char* name, - BasicType* arg_types, - BasicType return_type) - : SharkCompileInvariants(NULL, builder), - _target(target), - _arg_types(arg_types), - _return_type(return_type), - _lock_slot_offset(0) { initialize(name); } - - private: - void initialize(const char* name); - - private: - methodHandle _target; - BasicType* _arg_types; - BasicType _return_type; - llvm::Function* _function; - SharkStack* _stack; - llvm::Value* _oop_tmp_slot; - OopMapSet* _oop_maps; - int _receiver_slot_offset; - int _lock_slot_offset; - - // The method being compiled. - protected: - methodHandle target() const { - return _target; - } - - // Properties of the method. - protected: - int arg_size() const { - return target()->size_of_parameters(); - } - BasicType arg_type(int i) const { - return _arg_types[i]; - } - BasicType return_type() const { - return _return_type; - } - bool is_static() const { - return target()->is_static(); - } - bool is_synchronized() const { - return target()->is_synchronized(); - } - bool is_returning_oop() const { - return target()->is_returning_oop(); - } - - // The LLVM function we are building. - public: - llvm::Function* function() const { - return _function; - } - - // The Zero stack and our frame on it. - protected: - SharkStack* stack() const { - return _stack; - } - - // Temporary oop storage. - protected: - llvm::Value* oop_tmp_slot() const { - assert(is_static() || is_returning_oop(), "should be"); - return _oop_tmp_slot; - } - - // Information required by nmethod::new_native_nmethod(). - public: - int frame_size() const { - return stack()->oopmap_frame_size(); - } - ByteSize receiver_offset() const { - return in_ByteSize(_receiver_slot_offset * wordSize); - } - ByteSize lock_offset() const { - return in_ByteSize(_lock_slot_offset * wordSize); - } - OopMapSet* oop_maps() const { - return _oop_maps; - } - - // Helpers. - private: - llvm::BasicBlock* CreateBlock(const char* name = "") const { - return llvm::BasicBlock::Create(SharkContext::current(), name, function()); - } - llvm::Value* thread_state_address() const { - return builder()->CreateAddressOfStructEntry( - thread(), JavaThread::thread_state_offset(), - llvm::PointerType::getUnqual(SharkType::jint_type()), - "thread_state_address"); - } - llvm::Value* pending_exception_address() const { - return builder()->CreateAddressOfStructEntry( - thread(), Thread::pending_exception_offset(), - llvm::PointerType::getUnqual(SharkType::oop_type()), - "pending_exception_address"); - } - void CreateSetThreadState(JavaThreadState state) const { - builder()->CreateStore( - LLVMValue::jint_constant(state), thread_state_address()); - } - void CreateWriteMemorySerializePage() const { - builder()->CreateStore( - LLVMValue::jint_constant(1), - builder()->CreateIntToPtr( - builder()->CreateAdd( - LLVMValue::intptr_constant( - (intptr_t) os::get_memory_serialize_page()), - builder()->CreateAnd( - builder()->CreateLShr( - builder()->CreatePtrToInt(thread(), SharkType::intptr_type()), - LLVMValue::intptr_constant(os::get_serialize_page_shift_count())), - LLVMValue::intptr_constant(os::get_serialize_page_mask()))), - llvm::PointerType::getUnqual(SharkType::jint_type()))); - } - void CreateResetHandleBlock() const { - llvm::Value *active_handles = builder()->CreateValueOfStructEntry( - thread(), - JavaThread::active_handles_offset(), - SharkType::jniHandleBlock_type(), - "active_handles"); - builder()->CreateStore( - LLVMValue::intptr_constant(0), - builder()->CreateAddressOfStructEntry( - active_handles, - in_ByteSize(JNIHandleBlock::top_offset_in_bytes()), - llvm::PointerType::getUnqual(SharkType::intptr_type()), - "top")); - } - llvm::LoadInst* CreateLoadPendingException() const { - return builder()->CreateLoad( - pending_exception_address(), "pending_exception"); - } -}; - -#endif // SHARE_VM_SHARK_SHARKNATIVEWRAPPER_HPP diff --git a/src/hotspot/share/shark/sharkRuntime.cpp b/src/hotspot/share/shark/sharkRuntime.cpp deleted file mode 100644 index 30e17c23c00..00000000000 --- a/src/hotspot/share/shark/sharkRuntime.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "runtime/atomic.hpp" -#include "runtime/biasedLocking.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/thread.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkRuntime.hpp" -#include "utilities/macros.hpp" -#ifdef ZERO -# include "stack_zero.inline.hpp" -#endif - -using namespace llvm; - -JRT_ENTRY(int, SharkRuntime::find_exception_handler(JavaThread* thread, - int* indexes, - int num_indexes)) - constantPoolHandle pool(thread, method(thread)->constants()); - Klass* exc_klass = ((oop) tos_at(thread, 0))->klass(); - - for (int i = 0; i < num_indexes; i++) { - Klass* tmp = pool->klass_at(indexes[i], CHECK_0); - - if (exc_klass() == tmp) - return i; - - if (exc_klass()->is_subtype_of(tmp)) - return i; - } - - return -1; -JRT_END - -JRT_ENTRY(void, SharkRuntime::monitorenter(JavaThread* thread, - BasicObjectLock* lock)) - if (PrintBiasedLockingStatistics) - Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); - - Handle object(thread, lock->obj()); - assert(Universe::heap()->is_in_reserved_or_null(object()), "should be"); - if (UseBiasedLocking) { - // Retry fast entry if bias is revoked to avoid unnecessary inflation - ObjectSynchronizer::fast_enter(object, lock->lock(), true, CHECK); - } else { - ObjectSynchronizer::slow_enter(object, lock->lock(), CHECK); - } - assert(Universe::heap()->is_in_reserved_or_null(lock->obj()), "should be"); -JRT_END - -JRT_ENTRY(void, SharkRuntime::monitorexit(JavaThread* thread, - BasicObjectLock* lock)) - Handle object(thread, lock->obj()); - assert(Universe::heap()->is_in_reserved_or_null(object()), "should be"); - if (lock == NULL || object()->is_unlocked()) { - THROW(vmSymbols::java_lang_IllegalMonitorStateException()); - } - ObjectSynchronizer::slow_exit(object(), lock->lock(), thread); -JRT_END - -JRT_ENTRY(void, SharkRuntime::new_instance(JavaThread* thread, int index)) - Klass* k_oop = method(thread)->constants()->klass_at(index, CHECK); - InstanceKlass* klass = InstanceKlass::cast(k); - - // Make sure we are not instantiating an abstract klass - klass->check_valid_for_instantiation(true, CHECK); - - // Make sure klass is initialized - klass->initialize(CHECK); - - // At this point the class may not be fully initialized - // because of recursive initialization. If it is fully - // initialized & has_finalized is not set, we rewrite - // it into its fast version (Note: no locking is needed - // here since this is an atomic byte write and can be - // done more than once). - // - // Note: In case of classes with has_finalized we don't - // rewrite since that saves us an extra check in - // the fast version which then would call the - // slow version anyway (and do a call back into - // Java). - // If we have a breakpoint, then we don't rewrite - // because the _breakpoint bytecode would be lost. - oop obj = klass->allocate_instance(CHECK); - thread->set_vm_result(obj); -JRT_END - -JRT_ENTRY(void, SharkRuntime::newarray(JavaThread* thread, - BasicType type, - int size)) - oop obj = oopFactory::new_typeArray(type, size, CHECK); - thread->set_vm_result(obj); -JRT_END - -JRT_ENTRY(void, SharkRuntime::anewarray(JavaThread* thread, - int index, - int size)) - Klass* klass = method(thread)->constants()->klass_at(index, CHECK); - objArrayOop obj = oopFactory::new_objArray(klass, size, CHECK); - thread->set_vm_result(obj); -JRT_END - -JRT_ENTRY(void, SharkRuntime::multianewarray(JavaThread* thread, - int index, - int ndims, - int* dims)) - Klass* klass = method(thread)->constants()->klass_at(index, CHECK); - oop obj = ArrayKlass::cast(klass)->multi_allocate(ndims, dims, CHECK); - thread->set_vm_result(obj); -JRT_END - -JRT_ENTRY(void, SharkRuntime::register_finalizer(JavaThread* thread, - oop object)) - assert(oopDesc::is_oop(object), "should be"); - assert(object->klass()->has_finalizer(), "should have"); - InstanceKlass::register_finalizer(instanceOop(object), CHECK); -JRT_END - -JRT_ENTRY(void, SharkRuntime::throw_ArithmeticException(JavaThread* thread, - const char* file, - int line)) - Exceptions::_throw_msg( - thread, file, line, - vmSymbols::java_lang_ArithmeticException(), - ""); -JRT_END - -JRT_ENTRY(void, SharkRuntime::throw_ArrayIndexOutOfBoundsException( - JavaThread* thread, - const char* file, - int line, - int index)) - char msg[jintAsStringSize]; - snprintf(msg, sizeof(msg), "%d", index); - Exceptions::_throw_msg( - thread, file, line, - vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), - msg); -JRT_END - -JRT_ENTRY(void, SharkRuntime::throw_ClassCastException(JavaThread* thread, - const char* file, - int line)) - Exceptions::_throw_msg( - thread, file, line, - vmSymbols::java_lang_ClassCastException(), - ""); -JRT_END - -JRT_ENTRY(void, SharkRuntime::throw_NullPointerException(JavaThread* thread, - const char* file, - int line)) - Exceptions::_throw_msg( - thread, file, line, - vmSymbols::java_lang_NullPointerException(), - ""); -JRT_END - -// Non-VM calls -// Nothing in these must ever GC! - -void SharkRuntime::dump(const char *name, intptr_t value) { - oop valueOop = (oop) value; - tty->print("%s = ", name); - if (valueOop->is_oop(true)) - valueOop->print_on(tty); - else if (value >= ' ' && value <= '~') - tty->print("'%c' (%d)", value, value); - else - tty->print("%p", value); - tty->print_cr(""); -} - -bool SharkRuntime::is_subtype_of(Klass* check_klass, Klass* object_klass) { - return object_klass->is_subtype_of(check_klass); -} - -int SharkRuntime::uncommon_trap(JavaThread* thread, int trap_request) { - Thread *THREAD = thread; - - // In C2, uncommon_trap_blob creates a frame, so all the various - // deoptimization functions expect to find the frame of the method - // being deopted one frame down on the stack. We create a dummy - // frame to mirror this. - FakeStubFrame *stubframe = FakeStubFrame::build(CHECK_0); - thread->push_zero_frame(stubframe); - - // Initiate the trap - thread->set_last_Java_frame(); - Deoptimization::UnrollBlock *urb = - Deoptimization::uncommon_trap(thread, trap_request, Deoptimization::Unpack_uncommon_trap); - thread->reset_last_Java_frame(); - assert(urb->unpack_kind() == Deoptimization::Unpack_uncommon_trap, "expected Unpack_uncommon_trap"); - - // Pop our dummy frame and the frame being deoptimized - thread->pop_zero_frame(); - thread->pop_zero_frame(); - - // Push skeleton frames - int number_of_frames = urb->number_of_frames(); - for (int i = 0; i < number_of_frames; i++) { - intptr_t size = urb->frame_sizes()[i]; - InterpreterFrame *frame = InterpreterFrame::build(size, CHECK_0); - thread->push_zero_frame(frame); - } - - // Push another dummy frame - stubframe = FakeStubFrame::build(CHECK_0); - thread->push_zero_frame(stubframe); - - // Fill in the skeleton frames - thread->set_last_Java_frame(); - Deoptimization::unpack_frames(thread, Deoptimization::Unpack_uncommon_trap); - thread->reset_last_Java_frame(); - - // Pop our dummy frame - thread->pop_zero_frame(); - - // Fall back into the interpreter - return number_of_frames; -} - -FakeStubFrame* FakeStubFrame::build(TRAPS) { - ZeroStack *stack = ((JavaThread *) THREAD)->zero_stack(); - stack->overflow_check(header_words, CHECK_NULL); - - stack->push(0); // next_frame, filled in later - intptr_t *fp = stack->sp(); - assert(fp - stack->sp() == next_frame_off, "should be"); - - stack->push(FAKE_STUB_FRAME); - assert(fp - stack->sp() == frame_type_off, "should be"); - - return (FakeStubFrame *) fp; -} diff --git a/src/hotspot/share/shark/sharkRuntime.hpp b/src/hotspot/share/shark/sharkRuntime.hpp deleted file mode 100644 index 47e580c817e..00000000000 --- a/src/hotspot/share/shark/sharkRuntime.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKRUNTIME_HPP -#define SHARE_VM_SHARK_SHARKRUNTIME_HPP - -#include "memory/allocation.hpp" -#include "runtime/thread.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/llvmValue.hpp" - -class SharkRuntime : public AllStatic { - // VM calls - public: - static int find_exception_handler(JavaThread* thread, - int* indexes, - int num_indexes); - - static void monitorenter(JavaThread* thread, BasicObjectLock* lock); - static void monitorexit(JavaThread* thread, BasicObjectLock* lock); - - static void new_instance(JavaThread* thread, int index); - static void newarray(JavaThread* thread, BasicType type, int size); - static void anewarray(JavaThread* thread, int index, int size); - static void multianewarray(JavaThread* thread, - int index, - int ndims, - int* dims); - - static void register_finalizer(JavaThread* thread, oop object); - - static void throw_ArithmeticException(JavaThread* thread, - const char* file, - int line); - static void throw_ArrayIndexOutOfBoundsException(JavaThread* thread, - const char* file, - int line, - int index); - static void throw_ClassCastException(JavaThread* thread, - const char* file, - int line); - static void throw_NullPointerException(JavaThread* thread, - const char* file, - int line); - - // Helpers for VM calls - private: - static const SharkFrame* last_frame(JavaThread *thread) { - return thread->last_frame().zero_sharkframe(); - } - static Method* method(JavaThread *thread) { - return last_frame(thread)->method(); - } - static address bcp(JavaThread *thread, int bci) { - return method(thread)->code_base() + bci; - } - static int two_byte_index(JavaThread *thread, int bci) { - return Bytes::get_Java_u2(bcp(thread, bci) + 1); - } - static intptr_t tos_at(JavaThread *thread, int offset) { - return *(thread->zero_stack()->sp() + offset); - } - - // Non-VM calls - public: - static void dump(const char *name, intptr_t value); - static bool is_subtype_of(Klass* check_klass, Klass* object_klass); - static int uncommon_trap(JavaThread* thread, int trap_request); -}; - -#endif // SHARE_VM_SHARK_SHARKRUNTIME_HPP diff --git a/src/hotspot/share/shark/sharkStack.cpp b/src/hotspot/share/shark/sharkStack.cpp deleted file mode 100644 index c819586dd40..00000000000 --- a/src/hotspot/share/shark/sharkStack.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkFunction.hpp" -#include "shark/sharkNativeWrapper.hpp" -#include "shark/sharkStack.hpp" -#include "shark/sharkType.hpp" - -using namespace llvm; - -void SharkStack::initialize(Value* method) { - bool setup_sp_and_method = (method != NULL); - - int locals_words = max_locals(); - int extra_locals = locals_words - arg_size(); - int header_words = SharkFrame::header_words; - int monitor_words = max_monitors()*frame::interpreter_frame_monitor_size(); - int stack_words = max_stack(); - int frame_words = header_words + monitor_words + stack_words; - - _extended_frame_size = frame_words + locals_words; - - // Update the stack pointer - Value *stack_pointer = builder()->CreateSub( - CreateLoadStackPointer(), - LLVMValue::intptr_constant((frame_words + extra_locals) * wordSize)); - CreateStackOverflowCheck(stack_pointer); - if (setup_sp_and_method) - CreateStoreStackPointer(stack_pointer); - - // Create the frame - _frame = builder()->CreateIntToPtr( - stack_pointer, - PointerType::getUnqual( - ArrayType::get(SharkType::intptr_type(), extended_frame_size())), - "frame"); - int offset = 0; - - // Expression stack - _stack_slots_offset = offset; - offset += stack_words; - - // Monitors - _monitors_slots_offset = offset; - offset += monitor_words; - - // Temporary oop slot - _oop_tmp_slot_offset = offset++; - - // Method pointer - _method_slot_offset = offset++; - if (setup_sp_and_method) { - builder()->CreateStore( - method, slot_addr(method_slot_offset(), SharkType::Method_type())); - } - - // Unextended SP - builder()->CreateStore(stack_pointer, slot_addr(offset++)); - - // PC - _pc_slot_offset = offset++; - - // Frame header - builder()->CreateStore( - LLVMValue::intptr_constant(ZeroFrame::SHARK_FRAME), slot_addr(offset++)); - Value *fp = slot_addr(offset++); - - // Local variables - _locals_slots_offset = offset; - offset += locals_words; - - // Push the frame - assert(offset == extended_frame_size(), "should do"); - builder()->CreateStore(CreateLoadFramePointer(), fp); - CreateStoreFramePointer( - builder()->CreatePtrToInt(fp, SharkType::intptr_type())); -} - -// This function should match ZeroStack::overflow_check -void SharkStack::CreateStackOverflowCheck(Value* sp) { - BasicBlock *zero_ok = CreateBlock("zero_stack_ok"); - BasicBlock *overflow = CreateBlock("stack_overflow"); - BasicBlock *abi_ok = CreateBlock("abi_stack_ok"); - - // Check the Zero stack - builder()->CreateCondBr( - builder()->CreateICmpULT(sp, stack_base()), - overflow, zero_ok); - - // Check the ABI stack - builder()->SetInsertPoint(zero_ok); - Value *stack_top = builder()->CreateSub( - builder()->CreateValueOfStructEntry( - thread(), - Thread::stack_base_offset(), - SharkType::intptr_type(), - "abi_base"), - builder()->CreateValueOfStructEntry( - thread(), - Thread::stack_size_offset(), - SharkType::intptr_type(), - "abi_size")); - Value *free_stack = builder()->CreateSub( - builder()->CreatePtrToInt( - builder()->CreateGetFrameAddress(), - SharkType::intptr_type(), - "abi_sp"), - stack_top); - builder()->CreateCondBr( - builder()->CreateICmpULT( - free_stack, - LLVMValue::intptr_constant(JavaThread::stack_shadow_zone_size())), - overflow, abi_ok); - - // Handle overflows - builder()->SetInsertPoint(overflow); - builder()->CreateCall(builder()->throw_StackOverflowError(), thread()); - builder()->CreateRet(LLVMValue::jint_constant(0)); - - builder()->SetInsertPoint(abi_ok); -} - -Value* SharkStack::CreatePopFrame(int result_slots) { - assert(result_slots >= 0 && result_slots <= 2, "should be"); - int locals_to_pop = max_locals() - result_slots; - - Value *fp = CreateLoadFramePointer(); - Value *sp = builder()->CreateAdd( - fp, - LLVMValue::intptr_constant((1 + locals_to_pop) * wordSize)); - - CreateStoreStackPointer(sp); - CreateStoreFramePointer( - builder()->CreateLoad( - builder()->CreateIntToPtr( - fp, PointerType::getUnqual(SharkType::intptr_type())))); - - return sp; -} - -Value* SharkStack::slot_addr(int offset, - Type* type, - const char* name) const { - bool needs_cast = type && type != SharkType::intptr_type(); - - Value* result = builder()->CreateStructGEP( - _frame, offset, needs_cast ? "" : name); - - if (needs_cast) { - result = builder()->CreateBitCast( - result, PointerType::getUnqual(type), name); - } - return result; -} - -// The bits that differentiate stacks with normal and native frames on top - -SharkStack* SharkStack::CreateBuildAndPushFrame(SharkFunction* function, - Value* method) { - return new SharkStackWithNormalFrame(function, method); -} -SharkStack* SharkStack::CreateBuildAndPushFrame(SharkNativeWrapper* wrapper, - Value* method) { - return new SharkStackWithNativeFrame(wrapper, method); -} - -SharkStackWithNormalFrame::SharkStackWithNormalFrame(SharkFunction* function, - Value* method) - : SharkStack(function), _function(function) { - // For normal frames, the stack pointer and the method slot will - // be set during each decache, so it is not necessary to do them - // at the time the frame is created. However, we set them for - // non-PRODUCT builds to make crash dumps easier to understand. - initialize(PRODUCT_ONLY(NULL) NOT_PRODUCT(method)); -} -SharkStackWithNativeFrame::SharkStackWithNativeFrame(SharkNativeWrapper* wrp, - Value* method) - : SharkStack(wrp), _wrapper(wrp) { - initialize(method); -} - -int SharkStackWithNormalFrame::arg_size() const { - return function()->arg_size(); -} -int SharkStackWithNativeFrame::arg_size() const { - return wrapper()->arg_size(); -} - -int SharkStackWithNormalFrame::max_locals() const { - return function()->max_locals(); -} -int SharkStackWithNativeFrame::max_locals() const { - return wrapper()->arg_size(); -} - -int SharkStackWithNormalFrame::max_stack() const { - return function()->max_stack(); -} -int SharkStackWithNativeFrame::max_stack() const { - return 0; -} - -int SharkStackWithNormalFrame::max_monitors() const { - return function()->max_monitors(); -} -int SharkStackWithNativeFrame::max_monitors() const { - return wrapper()->is_synchronized() ? 1 : 0; -} - -BasicBlock* SharkStackWithNormalFrame::CreateBlock(const char* name) const { - return function()->CreateBlock(name); -} -BasicBlock* SharkStackWithNativeFrame::CreateBlock(const char* name) const { - return wrapper()->CreateBlock(name); -} - -address SharkStackWithNormalFrame::interpreter_entry_point() const { - return (address) CppInterpreter::normal_entry; -} -address SharkStackWithNativeFrame::interpreter_entry_point() const { - return (address) CppInterpreter::native_entry; -} - -#ifndef PRODUCT -void SharkStack::CreateAssertLastJavaSPIsNull() const { -#ifdef ASSERT - BasicBlock *fail = CreateBlock("assert_failed"); - BasicBlock *pass = CreateBlock("assert_ok"); - - builder()->CreateCondBr( - builder()->CreateICmpEQ( - builder()->CreateLoad(last_Java_sp_addr()), - LLVMValue::intptr_constant(0)), - pass, fail); - - builder()->SetInsertPoint(fail); - builder()->CreateShouldNotReachHere(__FILE__, __LINE__); - builder()->CreateUnreachable(); - - builder()->SetInsertPoint(pass); -#endif // ASSERT -} -#endif // !PRODUCT diff --git a/src/hotspot/share/shark/sharkStack.hpp b/src/hotspot/share/shark/sharkStack.hpp deleted file mode 100644 index 15e367f59bc..00000000000 --- a/src/hotspot/share/shark/sharkStack.hpp +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKSTACK_HPP -#define SHARE_VM_SHARK_SHARKSTACK_HPP - -#include "shark/llvmHeaders.hpp" -#include "shark/sharkInvariants.hpp" -#include "shark/sharkType.hpp" - -class SharkFunction; -class SharkNativeWrapper; -class SharkStackWithNormalFrame; -class SharkStackWithNativeFrame; - -class SharkStack : public SharkCompileInvariants { - public: - static SharkStack* CreateBuildAndPushFrame( - SharkFunction* function, llvm::Value* method); - static SharkStack* CreateBuildAndPushFrame( - SharkNativeWrapper* wrapper, llvm::Value* method); - - protected: - SharkStack(const SharkCompileInvariants* parent) - : SharkCompileInvariants(parent) {} - - protected: - void initialize(llvm::Value* method); - - protected: - void CreateStackOverflowCheck(llvm::Value* sp); - - // Properties of the method being compiled - protected: - virtual int arg_size() const = 0; - virtual int max_locals() const = 0; - virtual int max_stack() const = 0; - virtual int max_monitors() const = 0; - - // BasicBlock creation - protected: - virtual llvm::BasicBlock* CreateBlock(const char* name = "") const = 0; - - // Interpreter entry point for bailouts - protected: - virtual address interpreter_entry_point() const = 0; - - // Interface with the Zero stack - private: - llvm::Value* zero_stack() const { - return builder()->CreateAddressOfStructEntry( - thread(), - JavaThread::zero_stack_offset(), - SharkType::zeroStack_type(), - "zero_stack"); - } - llvm::Value* stack_base() const { - return builder()->CreateValueOfStructEntry( - zero_stack(), - ZeroStack::base_offset(), - SharkType::intptr_type(), - "stack_base"); - } - llvm::Value* stack_pointer_addr() const { - return builder()->CreateAddressOfStructEntry( - zero_stack(), - ZeroStack::sp_offset(), - llvm::PointerType::getUnqual(SharkType::intptr_type()), - "stack_pointer_addr"); - } - llvm::Value* frame_pointer_addr() const { - return builder()->CreateAddressOfStructEntry( - thread(), - JavaThread::top_zero_frame_offset(), - llvm::PointerType::getUnqual(SharkType::intptr_type()), - "frame_pointer_addr"); - } - - public: - llvm::LoadInst* CreateLoadStackPointer(const char *name = "") { - return builder()->CreateLoad(stack_pointer_addr(), name); - } - llvm::StoreInst* CreateStoreStackPointer(llvm::Value* value) { - return builder()->CreateStore(value, stack_pointer_addr()); - } - llvm::LoadInst* CreateLoadFramePointer(const char *name = "") { - return builder()->CreateLoad(frame_pointer_addr(), name); - } - llvm::StoreInst* CreateStoreFramePointer(llvm::Value* value) { - return builder()->CreateStore(value, frame_pointer_addr()); - } - llvm::Value* CreatePopFrame(int result_slots); - - // Interface with the frame anchor - private: - llvm::Value* last_Java_sp_addr() const { - return builder()->CreateAddressOfStructEntry( - thread(), - JavaThread::last_Java_sp_offset(), - llvm::PointerType::getUnqual(SharkType::intptr_type()), - "last_Java_sp_addr"); - } - llvm::Value* last_Java_fp_addr() const { - return builder()->CreateAddressOfStructEntry( - thread(), - JavaThread::last_Java_fp_offset(), - llvm::PointerType::getUnqual(SharkType::intptr_type()), - "last_Java_fp_addr"); - } - - public: - void CreateSetLastJavaFrame() { - // Note that whenever _last_Java_sp != NULL other anchor fields - // must be valid. The profiler apparently depends on this. - NOT_PRODUCT(CreateAssertLastJavaSPIsNull()); - builder()->CreateStore(CreateLoadFramePointer(), last_Java_fp_addr()); - // XXX There's last_Java_pc as well, but I don't think anything uses it - // Also XXX: should we fence here? Zero doesn't... - builder()->CreateStore(CreateLoadStackPointer(), last_Java_sp_addr()); - // Also also XXX: we could probably cache the sp (and the fp we know??) - } - void CreateResetLastJavaFrame() { - builder()->CreateStore(LLVMValue::intptr_constant(0), last_Java_sp_addr()); - } - - private: - void CreateAssertLastJavaSPIsNull() const PRODUCT_RETURN; - - // Our method's frame - private: - llvm::Value* _frame; - int _extended_frame_size; - int _stack_slots_offset; - - public: - int extended_frame_size() const { - return _extended_frame_size; - } - int oopmap_frame_size() const { - return extended_frame_size() - arg_size(); - } - - // Offsets of things in the frame - private: - int _monitors_slots_offset; - int _oop_tmp_slot_offset; - int _method_slot_offset; - int _pc_slot_offset; - int _locals_slots_offset; - - public: - int stack_slots_offset() const { - return _stack_slots_offset; - } - int oop_tmp_slot_offset() const { - return _oop_tmp_slot_offset; - } - int method_slot_offset() const { - return _method_slot_offset; - } - int pc_slot_offset() const { - return _pc_slot_offset; - } - int locals_slots_offset() const { - return _locals_slots_offset; - } - int monitor_offset(int index) const { - assert(index >= 0 && index < max_monitors(), "invalid monitor index"); - return _monitors_slots_offset + - (max_monitors() - 1 - index) * frame::interpreter_frame_monitor_size(); - } - int monitor_object_offset(int index) const { - return monitor_offset(index) + - (BasicObjectLock::obj_offset_in_bytes() >> LogBytesPerWord); - } - int monitor_header_offset(int index) const { - return monitor_offset(index) + - ((BasicObjectLock::lock_offset_in_bytes() + - BasicLock::displaced_header_offset_in_bytes()) >> LogBytesPerWord); - } - - // Addresses of things in the frame - public: - llvm::Value* slot_addr(int offset, - llvm::Type* type = NULL, - const char* name = "") const; - - llvm::Value* monitor_addr(int index) const { - return slot_addr( - monitor_offset(index), - SharkType::monitor_type(), - "monitor"); - } - llvm::Value* monitor_object_addr(int index) const { - return slot_addr( - monitor_object_offset(index), - SharkType::oop_type(), - "object_addr"); - } - llvm::Value* monitor_header_addr(int index) const { - return slot_addr( - monitor_header_offset(index), - SharkType::intptr_type(), - "displaced_header_addr"); - } - - // oopmap helpers - public: - static int oopmap_slot_munge(int offset) { - return offset << (LogBytesPerWord - LogBytesPerInt); - } - static VMReg slot2reg(int offset) { - return VMRegImpl::stack2reg(oopmap_slot_munge(offset)); - } -}; - -class SharkStackWithNormalFrame : public SharkStack { - friend class SharkStack; - - protected: - SharkStackWithNormalFrame(SharkFunction* function, llvm::Value* method); - - private: - SharkFunction* _function; - - private: - SharkFunction* function() const { - return _function; - } - - // Properties of the method being compiled - private: - int arg_size() const; - int max_locals() const; - int max_stack() const; - int max_monitors() const; - - // BasicBlock creation - private: - llvm::BasicBlock* CreateBlock(const char* name = "") const; - - // Interpreter entry point for bailouts - private: - address interpreter_entry_point() const; -}; - -class SharkStackWithNativeFrame : public SharkStack { - friend class SharkStack; - - protected: - SharkStackWithNativeFrame(SharkNativeWrapper* wrapper, llvm::Value* method); - - private: - SharkNativeWrapper* _wrapper; - - private: - SharkNativeWrapper* wrapper() const { - return _wrapper; - } - - // Properties of the method being compiled - private: - int arg_size() const; - int max_locals() const; - int max_stack() const; - int max_monitors() const; - - // BasicBlock creation - private: - llvm::BasicBlock* CreateBlock(const char* name = "") const; - - // Interpreter entry point for bailouts - private: - address interpreter_entry_point() const; -}; - -#endif // SHARE_VM_SHARK_SHARKSTACK_HPP diff --git a/src/hotspot/share/shark/sharkState.cpp b/src/hotspot/share/shark/sharkState.cpp deleted file mode 100644 index 87a5d5c6a42..00000000000 --- a/src/hotspot/share/shark/sharkState.cpp +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "ci/ciType.hpp" -#include "ci/ciTypeFlow.hpp" -#include "memory/allocation.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkCacheDecache.hpp" -#include "shark/sharkState.hpp" -#include "shark/sharkTopLevelBlock.hpp" -#include "shark/sharkType.hpp" -#include "shark/sharkValue.hpp" - -using namespace llvm; - -void SharkState::initialize(const SharkState *state) { - _locals = NEW_RESOURCE_ARRAY(SharkValue*, max_locals()); - _stack = NEW_RESOURCE_ARRAY(SharkValue*, max_stack()); - - NOT_PRODUCT(memset(_locals, 23, max_locals() * sizeof(SharkValue *))); - NOT_PRODUCT(memset(_stack, 23, max_stack() * sizeof(SharkValue *))); - _sp = _stack; - - if (state) { - for (int i = 0; i < max_locals(); i++) { - SharkValue *value = state->local(i); - if (value) - value = value->clone(); - set_local(i, value); - } - - for (int i = state->stack_depth() - 1; i >= 0; i--) { - SharkValue *value = state->stack(i); - if (value) - value = value->clone(); - push(value); - } - } - - set_num_monitors(state ? state->num_monitors() : 0); -} - -bool SharkState::equal_to(SharkState *other) { - if (target() != other->target()) - return false; - - if (method() != other->method()) - return false; - - if (oop_tmp() != other->oop_tmp()) - return false; - - if (max_locals() != other->max_locals()) - return false; - - if (stack_depth() != other->stack_depth()) - return false; - - if (num_monitors() != other->num_monitors()) - return false; - - if (has_safepointed() != other->has_safepointed()) - return false; - - // Local variables - for (int i = 0; i < max_locals(); i++) { - SharkValue *value = local(i); - SharkValue *other_value = other->local(i); - - if (value == NULL) { - if (other_value != NULL) - return false; - } - else { - if (other_value == NULL) - return false; - - if (!value->equal_to(other_value)) - return false; - } - } - - // Expression stack - for (int i = 0; i < stack_depth(); i++) { - SharkValue *value = stack(i); - SharkValue *other_value = other->stack(i); - - if (value == NULL) { - if (other_value != NULL) - return false; - } - else { - if (other_value == NULL) - return false; - - if (!value->equal_to(other_value)) - return false; - } - } - - return true; -} - -void SharkState::merge(SharkState* other, - BasicBlock* other_block, - BasicBlock* this_block) { - // Method - Value *this_method = this->method(); - Value *other_method = other->method(); - if (this_method != other_method) { - PHINode *phi = builder()->CreatePHI(SharkType::Method_type(), 0, "method"); - phi->addIncoming(this_method, this_block); - phi->addIncoming(other_method, other_block); - set_method(phi); - } - - // Temporary oop slot - Value *this_oop_tmp = this->oop_tmp(); - Value *other_oop_tmp = other->oop_tmp(); - if (this_oop_tmp != other_oop_tmp) { - assert(this_oop_tmp && other_oop_tmp, "can't merge NULL with non-NULL"); - PHINode *phi = builder()->CreatePHI(SharkType::oop_type(), 0, "oop_tmp"); - phi->addIncoming(this_oop_tmp, this_block); - phi->addIncoming(other_oop_tmp, other_block); - set_oop_tmp(phi); - } - - // Monitors - assert(this->num_monitors() == other->num_monitors(), "should be"); - - // Local variables - assert(this->max_locals() == other->max_locals(), "should be"); - for (int i = 0; i < max_locals(); i++) { - SharkValue *this_value = this->local(i); - SharkValue *other_value = other->local(i); - assert((this_value == NULL) == (other_value == NULL), "should be"); - if (this_value != NULL) { - char name[18]; - snprintf(name, sizeof(name), "local_%d_", i); - set_local(i, this_value->merge( - builder(), other_value, other_block, this_block, name)); - } - } - - // Expression stack - assert(this->stack_depth() == other->stack_depth(), "should be"); - for (int i = 0; i < stack_depth(); i++) { - SharkValue *this_value = this->stack(i); - SharkValue *other_value = other->stack(i); - assert((this_value == NULL) == (other_value == NULL), "should be"); - if (this_value != NULL) { - char name[18]; - snprintf(name, sizeof(name), "stack_%d_", i); - set_stack(i, this_value->merge( - builder(), other_value, other_block, this_block, name)); - } - } - - // Safepointed status - set_has_safepointed(this->has_safepointed() && other->has_safepointed()); -} - -void SharkState::replace_all(SharkValue* old_value, SharkValue* new_value) { - // Local variables - for (int i = 0; i < max_locals(); i++) { - if (local(i) == old_value) - set_local(i, new_value); - } - - // Expression stack - for (int i = 0; i < stack_depth(); i++) { - if (stack(i) == old_value) - set_stack(i, new_value); - } -} - -SharkNormalEntryState::SharkNormalEntryState(SharkTopLevelBlock* block, - Value* method) - : SharkState(block) { - assert(!block->stack_depth_at_entry(), "entry block shouldn't have stack"); - - // Local variables - for (int i = 0; i < max_locals(); i++) { - ciType *type = block->local_type_at_entry(i); - - SharkValue *value = NULL; - switch (type->basic_type()) { - case T_INT: - case T_LONG: - case T_FLOAT: - case T_DOUBLE: - case T_OBJECT: - case T_ARRAY: - if (i >= arg_size()) { - ShouldNotReachHere(); - } - value = SharkValue::create_generic(type, NULL, i == 0 && !is_static()); - break; - - case ciTypeFlow::StateVector::T_NULL: - value = SharkValue::null(); - break; - - case ciTypeFlow::StateVector::T_BOTTOM: - break; - - case ciTypeFlow::StateVector::T_LONG2: - case ciTypeFlow::StateVector::T_DOUBLE2: - break; - - default: - ShouldNotReachHere(); - } - set_local(i, value); - } - SharkNormalEntryCacher(block->function(), method).scan(this); -} - -SharkOSREntryState::SharkOSREntryState(SharkTopLevelBlock* block, - Value* method, - Value* osr_buf) - : SharkState(block) { - assert(block->stack_depth_at_entry() == 0, "entry block shouldn't have stack"); - set_num_monitors(block->ciblock()->monitor_count()); - - // Local variables - for (int i = 0; i < max_locals(); i++) { - ciType *type = block->local_type_at_entry(i); - - SharkValue *value = NULL; - switch (type->basic_type()) { - case T_INT: - case T_LONG: - case T_FLOAT: - case T_DOUBLE: - case T_OBJECT: - case T_ARRAY: - value = SharkValue::create_generic(type, NULL, false); - break; - - case ciTypeFlow::StateVector::T_NULL: - value = SharkValue::null(); - break; - - case ciTypeFlow::StateVector::T_BOTTOM: - break; - - case ciTypeFlow::StateVector::T_LONG2: - case ciTypeFlow::StateVector::T_DOUBLE2: - break; - - default: - ShouldNotReachHere(); - } - set_local(i, value); - } - SharkOSREntryCacher(block->function(), method, osr_buf).scan(this); -} - -SharkPHIState::SharkPHIState(SharkTopLevelBlock* block) - : SharkState(block), _block(block) { - BasicBlock *saved_insert_point = builder()->GetInsertBlock(); - builder()->SetInsertPoint(block->entry_block()); - char name[18]; - - // Method - set_method(builder()->CreatePHI(SharkType::Method_type(), 0, "method")); - - // Local variables - for (int i = 0; i < max_locals(); i++) { - ciType *type = block->local_type_at_entry(i); - if (type->basic_type() == (BasicType) ciTypeFlow::StateVector::T_NULL) { - // XXX we could do all kinds of clever stuff here - type = ciType::make(T_OBJECT); // XXX what about T_ARRAY? - } - - SharkValue *value = NULL; - switch (type->basic_type()) { - case T_INT: - case T_LONG: - case T_FLOAT: - case T_DOUBLE: - case T_OBJECT: - case T_ARRAY: - snprintf(name, sizeof(name), "local_%d_", i); - value = SharkValue::create_phi( - type, builder()->CreatePHI(SharkType::to_stackType(type), 0, name)); - break; - - case T_ADDRESS: - value = SharkValue::address_constant(type->as_return_address()->bci()); - break; - - case ciTypeFlow::StateVector::T_BOTTOM: - break; - - case ciTypeFlow::StateVector::T_LONG2: - case ciTypeFlow::StateVector::T_DOUBLE2: - break; - - default: - ShouldNotReachHere(); - } - set_local(i, value); - } - - // Expression stack - for (int i = 0; i < block->stack_depth_at_entry(); i++) { - ciType *type = block->stack_type_at_entry(i); - if (type->basic_type() == (BasicType) ciTypeFlow::StateVector::T_NULL) { - // XXX we could do all kinds of clever stuff here - type = ciType::make(T_OBJECT); // XXX what about T_ARRAY? - } - - SharkValue *value = NULL; - switch (type->basic_type()) { - case T_INT: - case T_LONG: - case T_FLOAT: - case T_DOUBLE: - case T_OBJECT: - case T_ARRAY: - snprintf(name, sizeof(name), "stack_%d_", i); - value = SharkValue::create_phi( - type, builder()->CreatePHI(SharkType::to_stackType(type), 0, name)); - break; - - case T_ADDRESS: - value = SharkValue::address_constant(type->as_return_address()->bci()); - break; - - case ciTypeFlow::StateVector::T_LONG2: - case ciTypeFlow::StateVector::T_DOUBLE2: - break; - - default: - ShouldNotReachHere(); - } - push(value); - } - - // Monitors - set_num_monitors(block->ciblock()->monitor_count()); - - builder()->SetInsertPoint(saved_insert_point); -} - -void SharkPHIState::add_incoming(SharkState* incoming_state) { - BasicBlock *predecessor = builder()->GetInsertBlock(); - - // Method - ((PHINode *) method())->addIncoming(incoming_state->method(), predecessor); - - // Local variables - for (int i = 0; i < max_locals(); i++) { - if (local(i) != NULL) - local(i)->addIncoming(incoming_state->local(i), predecessor); - } - - // Expression stack - int stack_depth = block()->stack_depth_at_entry(); - assert(stack_depth == incoming_state->stack_depth(), "should be"); - for (int i = 0; i < stack_depth; i++) { - assert((stack(i) == NULL) == (incoming_state->stack(i) == NULL), "oops"); - if (stack(i)) - stack(i)->addIncoming(incoming_state->stack(i), predecessor); - } - - // Monitors - assert(num_monitors() == incoming_state->num_monitors(), "should be"); - - // Temporary oop slot - assert(oop_tmp() == incoming_state->oop_tmp(), "should be"); -} diff --git a/src/hotspot/share/shark/sharkState.hpp b/src/hotspot/share/shark/sharkState.hpp deleted file mode 100644 index d698bb2c7f1..00000000000 --- a/src/hotspot/share/shark/sharkState.hpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKSTATE_HPP -#define SHARE_VM_SHARK_SHARKSTATE_HPP - -#include "ci/ciMethod.hpp" -#include "memory/allocation.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkInvariants.hpp" -#include "shark/sharkValue.hpp" - -class SharkState : public SharkTargetInvariants { - public: - SharkState(const SharkTargetInvariants* parent) - : SharkTargetInvariants(parent), - _method(NULL), - _oop_tmp(NULL), - _has_safepointed(false) { initialize(NULL); } - - SharkState(const SharkState* state) - : SharkTargetInvariants(state), - _method(state->_method), - _oop_tmp(state->_oop_tmp), - _has_safepointed(state->_has_safepointed) { initialize(state); } - - private: - void initialize(const SharkState* state); - - private: - llvm::Value* _method; - SharkValue** _locals; - SharkValue** _stack; - SharkValue** _sp; - int _num_monitors; - llvm::Value* _oop_tmp; - bool _has_safepointed; - - // Method - public: - llvm::Value** method_addr() { - return &_method; - } - llvm::Value* method() const { - return _method; - } - protected: - void set_method(llvm::Value* method) { - _method = method; - } - - // Local variables - public: - SharkValue** local_addr(int index) const { - assert(index >= 0 && index < max_locals(), "bad local variable index"); - return &_locals[index]; - } - SharkValue* local(int index) const { - return *local_addr(index); - } - void set_local(int index, SharkValue* value) { - *local_addr(index) = value; - } - - // Expression stack - public: - SharkValue** stack_addr(int slot) const { - assert(slot >= 0 && slot < stack_depth(), "bad stack slot"); - return &_sp[-(slot + 1)]; - } - SharkValue* stack(int slot) const { - return *stack_addr(slot); - } - protected: - void set_stack(int slot, SharkValue* value) { - *stack_addr(slot) = value; - } - public: - int stack_depth() const { - return _sp - _stack; - } - void push(SharkValue* value) { - assert(stack_depth() < max_stack(), "stack overrun"); - *(_sp++) = value; - } - SharkValue* pop() { - assert(stack_depth() > 0, "stack underrun"); - return *(--_sp); - } - - // Monitors - public: - int num_monitors() const { - return _num_monitors; - } - void set_num_monitors(int num_monitors) { - _num_monitors = num_monitors; - } - - // Temporary oop slot - public: - llvm::Value** oop_tmp_addr() { - return &_oop_tmp; - } - llvm::Value* oop_tmp() const { - return _oop_tmp; - } - void set_oop_tmp(llvm::Value* oop_tmp) { - _oop_tmp = oop_tmp; - } - - // Safepointed status - public: - bool has_safepointed() const { - return _has_safepointed; - } - void set_has_safepointed(bool has_safepointed) { - _has_safepointed = has_safepointed; - } - - // Comparison - public: - bool equal_to(SharkState* other); - - // Copy and merge - public: - SharkState* copy() const { - return new SharkState(this); - } - void merge(SharkState* other, - llvm::BasicBlock* other_block, - llvm::BasicBlock* this_block); - - // Value replacement - public: - void replace_all(SharkValue* old_value, SharkValue* new_value); -}; - -class SharkTopLevelBlock; - -// SharkNormalEntryState objects are used to create the state -// that the method will be entered with for a normal invocation. -class SharkNormalEntryState : public SharkState { - public: - SharkNormalEntryState(SharkTopLevelBlock* block, - llvm::Value* method); -}; - -// SharkOSREntryState objects are used to create the state -// that the method will be entered with for an OSR invocation. -class SharkOSREntryState : public SharkState { - public: - SharkOSREntryState(SharkTopLevelBlock* block, - llvm::Value* method, - llvm::Value* osr_buf); -}; - -// SharkPHIState objects are used to manage the entry state -// for blocks with more than one entry path or for blocks -// entered from blocks that will be compiled later. -class SharkPHIState : public SharkState { - public: - SharkPHIState(SharkTopLevelBlock* block); - - private: - SharkTopLevelBlock* _block; - - private: - SharkTopLevelBlock* block() const { - return _block; - } - - public: - void add_incoming(SharkState* incoming_state); -}; - -#endif // SHARE_VM_SHARK_SHARKSTATE_HPP diff --git a/src/hotspot/share/shark/sharkStateScanner.cpp b/src/hotspot/share/shark/sharkStateScanner.cpp deleted file mode 100644 index 26a1fc581a0..00000000000 --- a/src/hotspot/share/shark/sharkStateScanner.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "shark/sharkState.hpp" -#include "shark/sharkStateScanner.hpp" - -using namespace llvm; - -void SharkStateScanner::scan(SharkState* state) { - start_frame(); - - // Expression stack - stack_integrity_checks(state); - start_stack(state->stack_depth()); - for (int i = state->stack_depth() - 1; i >= 0; i--) { - process_stack_slot( - i, - state->stack_addr(i), - stack()->stack_slots_offset() + - i + max_stack() - state->stack_depth()); - } - end_stack(); - - // Monitors - start_monitors(state->num_monitors()); - for (int i = 0; i < state->num_monitors(); i++) { - process_monitor( - i, - stack()->monitor_offset(i), - stack()->monitor_object_offset(i)); - } - end_monitors(); - - // Frame header - start_frame_header(); - process_oop_tmp_slot( - state->oop_tmp_addr(), stack()->oop_tmp_slot_offset()); - process_method_slot(state->method_addr(), stack()->method_slot_offset()); - process_pc_slot(stack()->pc_slot_offset()); - end_frame_header(); - - // Local variables - locals_integrity_checks(state); - start_locals(); - for (int i = 0; i < max_locals(); i++) { - process_local_slot( - i, - state->local_addr(i), - stack()->locals_slots_offset() + max_locals() - 1 - i); - } - end_locals(); - - end_frame(); -} - -#ifndef PRODUCT -void SharkStateScanner::stack_integrity_checks(SharkState* state) { - for (int i = 0; i < state->stack_depth(); i++) { - if (state->stack(i)) { - if (state->stack(i)->is_two_word()) - assert(state->stack(i - 1) == NULL, "should be"); - } - else { - assert(state->stack(i + 1)->is_two_word(), "should be"); - } - } -} - -void SharkStateScanner::locals_integrity_checks(SharkState* state) { - for (int i = 0; i < max_locals(); i++) { - if (state->local(i)) { - if (state->local(i)->is_two_word()) - assert(state->local(i + 1) == NULL, "should be"); - } - } -} -#endif // !PRODUCT diff --git a/src/hotspot/share/shark/sharkStateScanner.hpp b/src/hotspot/share/shark/sharkStateScanner.hpp deleted file mode 100644 index 115d4a3a3e4..00000000000 --- a/src/hotspot/share/shark/sharkStateScanner.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKSTATESCANNER_HPP -#define SHARE_VM_SHARK_SHARKSTATESCANNER_HPP - -#include "memory/allocation.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkFunction.hpp" -#include "shark/sharkInvariants.hpp" - -class SharkState; - -class SharkStateScanner : public SharkTargetInvariants { - protected: - SharkStateScanner(SharkFunction* function) - : SharkTargetInvariants(function), _stack(function->stack()) {} - - private: - SharkStack* _stack; - - protected: - SharkStack* stack() const { - return _stack; - } - - // Scan the frame - public: - void scan(SharkState* state); - - // Callbacks - // Note that the offsets supplied to the various process_* callbacks - // are specified in wordSize words from the frame's unextended_sp. - protected: - virtual void start_frame() {} - - virtual void start_stack(int stack_depth) {} - virtual void process_stack_slot(int index, SharkValue** value, int offset) {} - virtual void end_stack() {} - - virtual void start_monitors(int num_monitors) {} - virtual void process_monitor(int index, int box_offset, int obj_offset) {} - virtual void end_monitors() {} - - virtual void start_frame_header() {} - virtual void process_oop_tmp_slot(llvm::Value** value, int offset) {} - virtual void process_method_slot(llvm::Value** value, int offset) {} - virtual void process_pc_slot(int offset) {} - virtual void end_frame_header() {} - - virtual void start_locals() {} - virtual void process_local_slot(int index, SharkValue** value, int offset) {} - virtual void end_locals() {} - - virtual void end_frame() {} - - // Integrity checks - private: - void stack_integrity_checks(SharkState* state) PRODUCT_RETURN; - void locals_integrity_checks(SharkState* state) PRODUCT_RETURN; -}; - -#endif // SHARE_VM_SHARK_SHARKSTATESCANNER_HPP diff --git a/src/hotspot/share/shark/sharkTopLevelBlock.cpp b/src/hotspot/share/shark/sharkTopLevelBlock.cpp deleted file mode 100644 index 2d274673b51..00000000000 --- a/src/hotspot/share/shark/sharkTopLevelBlock.cpp +++ /dev/null @@ -1,2043 +0,0 @@ -/* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "ci/ciField.hpp" -#include "ci/ciInstance.hpp" -#include "ci/ciObjArrayKlass.hpp" -#include "ci/ciStreams.hpp" -#include "ci/ciType.hpp" -#include "ci/ciTypeFlow.hpp" -#include "interpreter/bytecodes.hpp" -#include "memory/allocation.hpp" -#include "runtime/deoptimization.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/llvmValue.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkCacheDecache.hpp" -#include "shark/sharkConstant.hpp" -#include "shark/sharkInliner.hpp" -#include "shark/sharkState.hpp" -#include "shark/sharkTopLevelBlock.hpp" -#include "shark/sharkValue.hpp" -#include "shark/shark_globals.hpp" -#include "utilities/debug.hpp" - -using namespace llvm; - -void SharkTopLevelBlock::scan_for_traps() { - // If typeflow found a trap then don't scan past it - int limit_bci = ciblock()->has_trap() ? ciblock()->trap_bci() : limit(); - - // Scan the bytecode for traps that are always hit - iter()->reset_to_bci(start()); - while (iter()->next_bci() < limit_bci) { - iter()->next(); - - ciField *field; - ciMethod *method; - ciInstanceKlass *klass; - bool will_link; - bool is_field; - - switch (bc()) { - case Bytecodes::_ldc: - case Bytecodes::_ldc_w: - case Bytecodes::_ldc2_w: - if (!SharkConstant::for_ldc(iter())->is_loaded()) { - set_trap( - Deoptimization::make_trap_request( - Deoptimization::Reason_uninitialized, - Deoptimization::Action_reinterpret), bci()); - return; - } - break; - - case Bytecodes::_getfield: - case Bytecodes::_getstatic: - case Bytecodes::_putfield: - case Bytecodes::_putstatic: - field = iter()->get_field(will_link); - assert(will_link, "typeflow responsibility"); - is_field = (bc() == Bytecodes::_getfield || bc() == Bytecodes::_putfield); - - // If the bytecode does not match the field then bail out to - // the interpreter to throw an IncompatibleClassChangeError - if (is_field == field->is_static()) { - set_trap( - Deoptimization::make_trap_request( - Deoptimization::Reason_unhandled, - Deoptimization::Action_none), bci()); - return; - } - - // Bail out if we are trying to access a static variable - // before the class initializer has completed. - if (!is_field && !field->holder()->is_initialized()) { - if (!static_field_ok_in_clinit(field)) { - set_trap( - Deoptimization::make_trap_request( - Deoptimization::Reason_uninitialized, - Deoptimization::Action_reinterpret), bci()); - return; - } - } - break; - - case Bytecodes::_invokestatic: - case Bytecodes::_invokespecial: - case Bytecodes::_invokevirtual: - case Bytecodes::_invokeinterface: - ciSignature* sig; - method = iter()->get_method(will_link, &sig); - assert(will_link, "typeflow responsibility"); - // We can't compile calls to method handle intrinsics, because we use - // the interpreter entry points and they expect the top frame to be an - // interpreter frame. We need to implement the intrinsics for Shark. - if (method->is_method_handle_intrinsic() || method->is_compiled_lambda_form()) { - if (SharkPerformanceWarnings) { - warning("JSR292 optimization not yet implemented in Shark"); - } - set_trap( - Deoptimization::make_trap_request( - Deoptimization::Reason_unhandled, - Deoptimization::Action_make_not_compilable), bci()); - return; - } - if (!method->holder()->is_linked()) { - set_trap( - Deoptimization::make_trap_request( - Deoptimization::Reason_uninitialized, - Deoptimization::Action_reinterpret), bci()); - return; - } - - if (bc() == Bytecodes::_invokevirtual) { - klass = ciEnv::get_instance_klass_for_declared_method_holder( - iter()->get_declared_method_holder()); - if (!klass->is_linked()) { - set_trap( - Deoptimization::make_trap_request( - Deoptimization::Reason_uninitialized, - Deoptimization::Action_reinterpret), bci()); - return; - } - } - break; - - case Bytecodes::_new: - klass = iter()->get_klass(will_link)->as_instance_klass(); - assert(will_link, "typeflow responsibility"); - - // Bail out if the class is unloaded - if (iter()->is_unresolved_klass() || !klass->is_initialized()) { - set_trap( - Deoptimization::make_trap_request( - Deoptimization::Reason_uninitialized, - Deoptimization::Action_reinterpret), bci()); - return; - } - - // Bail out if the class cannot be instantiated - if (klass->is_abstract() || klass->is_interface() || - klass->name() == ciSymbol::java_lang_Class()) { - set_trap( - Deoptimization::make_trap_request( - Deoptimization::Reason_unhandled, - Deoptimization::Action_reinterpret), bci()); - return; - } - break; - case Bytecodes::_invokedynamic: - case Bytecodes::_invokehandle: - if (SharkPerformanceWarnings) { - warning("JSR292 optimization not yet implemented in Shark"); - } - set_trap( - Deoptimization::make_trap_request( - Deoptimization::Reason_unhandled, - Deoptimization::Action_make_not_compilable), bci()); - return; - } - } - - // Trap if typeflow trapped (and we didn't before) - if (ciblock()->has_trap()) { - set_trap( - Deoptimization::make_trap_request( - Deoptimization::Reason_unloaded, - Deoptimization::Action_reinterpret, - ciblock()->trap_index()), ciblock()->trap_bci()); - return; - } -} - -bool SharkTopLevelBlock::static_field_ok_in_clinit(ciField* field) { - assert(field->is_static(), "should be"); - - // This code is lifted pretty much verbatim from C2's - // Parse::static_field_ok_in_clinit() in parse3.cpp. - bool access_OK = false; - if (target()->holder()->is_subclass_of(field->holder())) { - if (target()->is_static()) { - if (target()->name() == ciSymbol::class_initializer_name()) { - // It's OK to access static fields from the class initializer - access_OK = true; - } - } - else { - if (target()->name() == ciSymbol::object_initializer_name()) { - // It's also OK to access static fields inside a constructor, - // because any thread calling the constructor must first have - // synchronized on the class by executing a "new" bytecode. - access_OK = true; - } - } - } - return access_OK; -} - -SharkState* SharkTopLevelBlock::entry_state() { - if (_entry_state == NULL) { - assert(needs_phis(), "should do"); - _entry_state = new SharkPHIState(this); - } - return _entry_state; -} - -void SharkTopLevelBlock::add_incoming(SharkState* incoming_state) { - if (needs_phis()) { - ((SharkPHIState *) entry_state())->add_incoming(incoming_state); - } - else if (_entry_state == NULL) { - _entry_state = incoming_state; - } - else { - assert(entry_state()->equal_to(incoming_state), "should be"); - } -} - -void SharkTopLevelBlock::enter(SharkTopLevelBlock* predecessor, - bool is_exception) { - // This block requires phis: - // - if it is entered more than once - // - if it is an exception handler, because in which - // case we assume it's entered more than once. - // - if the predecessor will be compiled after this - // block, in which case we can't simple propagate - // the state forward. - if (!needs_phis() && - (entered() || - is_exception || - (predecessor && predecessor->index() >= index()))) - _needs_phis = true; - - // Recurse into the tree - if (!entered()) { - _entered = true; - - scan_for_traps(); - if (!has_trap()) { - for (int i = 0; i < num_successors(); i++) { - successor(i)->enter(this, false); - } - } - compute_exceptions(); - for (int i = 0; i < num_exceptions(); i++) { - SharkTopLevelBlock *handler = exception(i); - if (handler) - handler->enter(this, true); - } - } -} - -void SharkTopLevelBlock::initialize() { - char name[28]; - snprintf(name, sizeof(name), - "bci_%d%s", - start(), is_backedge_copy() ? "_backedge_copy" : ""); - _entry_block = function()->CreateBlock(name); -} - -void SharkTopLevelBlock::decache_for_Java_call(ciMethod *callee) { - SharkJavaCallDecacher(function(), bci(), callee).scan(current_state()); - for (int i = 0; i < callee->arg_size(); i++) - xpop(); -} - -void SharkTopLevelBlock::cache_after_Java_call(ciMethod *callee) { - if (callee->return_type()->size()) { - ciType *type; - switch (callee->return_type()->basic_type()) { - case T_BOOLEAN: - case T_BYTE: - case T_CHAR: - case T_SHORT: - type = ciType::make(T_INT); - break; - - default: - type = callee->return_type(); - } - - push(SharkValue::create_generic(type, NULL, false)); - } - SharkJavaCallCacher(function(), callee).scan(current_state()); -} - -void SharkTopLevelBlock::decache_for_VM_call() { - SharkVMCallDecacher(function(), bci()).scan(current_state()); -} - -void SharkTopLevelBlock::cache_after_VM_call() { - SharkVMCallCacher(function()).scan(current_state()); -} - -void SharkTopLevelBlock::decache_for_trap() { - SharkTrapDecacher(function(), bci()).scan(current_state()); -} - -void SharkTopLevelBlock::emit_IR() { - builder()->SetInsertPoint(entry_block()); - - // Parse the bytecode - parse_bytecode(start(), limit()); - - // If this block falls through to the next then it won't have been - // terminated by a bytecode and we have to add the branch ourselves - if (falls_through() && !has_trap()) - do_branch(ciTypeFlow::FALL_THROUGH); -} - -SharkTopLevelBlock* SharkTopLevelBlock::bci_successor(int bci) const { - // XXX now with Linear Search Technology (tm) - for (int i = 0; i < num_successors(); i++) { - ciTypeFlow::Block *successor = ciblock()->successors()->at(i); - if (successor->start() == bci) - return function()->block(successor->pre_order()); - } - ShouldNotReachHere(); -} - -void SharkTopLevelBlock::do_zero_check(SharkValue *value) { - if (value->is_phi() && value->as_phi()->all_incomers_zero_checked()) { - function()->add_deferred_zero_check(this, value); - } - else { - BasicBlock *continue_block = function()->CreateBlock("not_zero"); - SharkState *saved_state = current_state(); - set_current_state(saved_state->copy()); - zero_check_value(value, continue_block); - builder()->SetInsertPoint(continue_block); - set_current_state(saved_state); - } - - value->set_zero_checked(true); -} - -void SharkTopLevelBlock::do_deferred_zero_check(SharkValue* value, - int bci, - SharkState* saved_state, - BasicBlock* continue_block) { - if (value->as_phi()->all_incomers_zero_checked()) { - builder()->CreateBr(continue_block); - } - else { - iter()->force_bci(start()); - set_current_state(saved_state); - zero_check_value(value, continue_block); - } -} - -void SharkTopLevelBlock::zero_check_value(SharkValue* value, - BasicBlock* continue_block) { - BasicBlock *zero_block = builder()->CreateBlock(continue_block, "zero"); - - Value *a, *b; - switch (value->basic_type()) { - case T_BYTE: - case T_CHAR: - case T_SHORT: - case T_INT: - a = value->jint_value(); - b = LLVMValue::jint_constant(0); - break; - case T_LONG: - a = value->jlong_value(); - b = LLVMValue::jlong_constant(0); - break; - case T_OBJECT: - case T_ARRAY: - a = value->jobject_value(); - b = LLVMValue::LLVMValue::null(); - break; - default: - tty->print_cr("Unhandled type %s", type2name(value->basic_type())); - ShouldNotReachHere(); - } - - builder()->CreateCondBr( - builder()->CreateICmpNE(a, b), continue_block, zero_block); - - builder()->SetInsertPoint(zero_block); - if (value->is_jobject()) { - call_vm( - builder()->throw_NullPointerException(), - builder()->CreateIntToPtr( - LLVMValue::intptr_constant((intptr_t) __FILE__), - PointerType::getUnqual(SharkType::jbyte_type())), - LLVMValue::jint_constant(__LINE__), - EX_CHECK_NONE); - } - else { - call_vm( - builder()->throw_ArithmeticException(), - builder()->CreateIntToPtr( - LLVMValue::intptr_constant((intptr_t) __FILE__), - PointerType::getUnqual(SharkType::jbyte_type())), - LLVMValue::jint_constant(__LINE__), - EX_CHECK_NONE); - } - - Value *pending_exception = get_pending_exception(); - clear_pending_exception(); - handle_exception(pending_exception, EX_CHECK_FULL); -} - -void SharkTopLevelBlock::check_bounds(SharkValue* array, SharkValue* index) { - BasicBlock *out_of_bounds = function()->CreateBlock("out_of_bounds"); - BasicBlock *in_bounds = function()->CreateBlock("in_bounds"); - - Value *length = builder()->CreateArrayLength(array->jarray_value()); - // we use an unsigned comparison to catch negative values - builder()->CreateCondBr( - builder()->CreateICmpULT(index->jint_value(), length), - in_bounds, out_of_bounds); - - builder()->SetInsertPoint(out_of_bounds); - SharkState *saved_state = current_state()->copy(); - - call_vm( - builder()->throw_ArrayIndexOutOfBoundsException(), - builder()->CreateIntToPtr( - LLVMValue::intptr_constant((intptr_t) __FILE__), - PointerType::getUnqual(SharkType::jbyte_type())), - LLVMValue::jint_constant(__LINE__), - index->jint_value(), - EX_CHECK_NONE); - - Value *pending_exception = get_pending_exception(); - clear_pending_exception(); - handle_exception(pending_exception, EX_CHECK_FULL); - - set_current_state(saved_state); - - builder()->SetInsertPoint(in_bounds); -} - -void SharkTopLevelBlock::check_pending_exception(int action) { - assert(action & EAM_CHECK, "should be"); - - BasicBlock *exception = function()->CreateBlock("exception"); - BasicBlock *no_exception = function()->CreateBlock("no_exception"); - - Value *pending_exception = get_pending_exception(); - builder()->CreateCondBr( - builder()->CreateICmpEQ(pending_exception, LLVMValue::null()), - no_exception, exception); - - builder()->SetInsertPoint(exception); - SharkState *saved_state = current_state()->copy(); - if (action & EAM_MONITOR_FUDGE) { - // The top monitor is marked live, but the exception was thrown - // while setting it up so we need to mark it dead before we enter - // any exception handlers as they will not expect it to be there. - set_num_monitors(num_monitors() - 1); - action ^= EAM_MONITOR_FUDGE; - } - clear_pending_exception(); - handle_exception(pending_exception, action); - set_current_state(saved_state); - - builder()->SetInsertPoint(no_exception); -} - -void SharkTopLevelBlock::compute_exceptions() { - ciExceptionHandlerStream str(target(), start()); - - int exc_count = str.count(); - _exc_handlers = new GrowableArray(exc_count); - _exceptions = new GrowableArray(exc_count); - - int index = 0; - for (; !str.is_done(); str.next()) { - ciExceptionHandler *handler = str.handler(); - if (handler->handler_bci() == -1) - break; - _exc_handlers->append(handler); - - // Try and get this exception's handler from typeflow. We should - // do it this way always, really, except that typeflow sometimes - // doesn't record exceptions, even loaded ones, and sometimes it - // returns them with a different handler bci. Why??? - SharkTopLevelBlock *block = NULL; - ciInstanceKlass* klass; - if (handler->is_catch_all()) { - klass = java_lang_Throwable_klass(); - } - else { - klass = handler->catch_klass(); - } - for (int i = 0; i < ciblock()->exceptions()->length(); i++) { - if (klass == ciblock()->exc_klasses()->at(i)) { - block = function()->block(ciblock()->exceptions()->at(i)->pre_order()); - if (block->start() == handler->handler_bci()) - break; - else - block = NULL; - } - } - - // If typeflow let us down then try and figure it out ourselves - if (block == NULL) { - for (int i = 0; i < function()->block_count(); i++) { - SharkTopLevelBlock *candidate = function()->block(i); - if (candidate->start() == handler->handler_bci()) { - if (block != NULL) { - NOT_PRODUCT(warning("there may be trouble ahead")); - block = NULL; - break; - } - block = candidate; - } - } - } - _exceptions->append(block); - } -} - -void SharkTopLevelBlock::handle_exception(Value* exception, int action) { - if (action & EAM_HANDLE && num_exceptions() != 0) { - // Clear the stack and push the exception onto it - while (xstack_depth()) - pop(); - push(SharkValue::create_jobject(exception, true)); - - // Work out how many options we have to check - bool has_catch_all = exc_handler(num_exceptions() - 1)->is_catch_all(); - int num_options = num_exceptions(); - if (has_catch_all) - num_options--; - - // Marshal any non-catch-all handlers - if (num_options > 0) { - bool all_loaded = true; - for (int i = 0; i < num_options; i++) { - if (!exc_handler(i)->catch_klass()->is_loaded()) { - all_loaded = false; - break; - } - } - - if (all_loaded) - marshal_exception_fast(num_options); - else - marshal_exception_slow(num_options); - } - - // Install the catch-all handler, if present - if (has_catch_all) { - SharkTopLevelBlock* handler = this->exception(num_options); - assert(handler != NULL, "catch-all handler cannot be unloaded"); - - builder()->CreateBr(handler->entry_block()); - handler->add_incoming(current_state()); - return; - } - } - - // No exception handler was found; unwind and return - handle_return(T_VOID, exception); -} - -void SharkTopLevelBlock::marshal_exception_fast(int num_options) { - Value *exception_klass = builder()->CreateValueOfStructEntry( - xstack(0)->jobject_value(), - in_ByteSize(oopDesc::klass_offset_in_bytes()), - SharkType::klass_type(), - "exception_klass"); - - for (int i = 0; i < num_options; i++) { - Value *check_klass = - builder()->CreateInlineMetadata(exc_handler(i)->catch_klass(), SharkType::klass_type()); - - BasicBlock *not_exact = function()->CreateBlock("not_exact"); - BasicBlock *not_subtype = function()->CreateBlock("not_subtype"); - - builder()->CreateCondBr( - builder()->CreateICmpEQ(check_klass, exception_klass), - handler_for_exception(i), not_exact); - - builder()->SetInsertPoint(not_exact); - builder()->CreateCondBr( - builder()->CreateICmpNE( - builder()->CreateCall2( - builder()->is_subtype_of(), check_klass, exception_klass), - LLVMValue::jbyte_constant(0)), - handler_for_exception(i), not_subtype); - - builder()->SetInsertPoint(not_subtype); - } -} - -void SharkTopLevelBlock::marshal_exception_slow(int num_options) { - int *indexes = NEW_RESOURCE_ARRAY(int, num_options); - for (int i = 0; i < num_options; i++) - indexes[i] = exc_handler(i)->catch_klass_index(); - - Value *index = call_vm( - builder()->find_exception_handler(), - builder()->CreateInlineData( - indexes, - num_options * sizeof(int), - PointerType::getUnqual(SharkType::jint_type())), - LLVMValue::jint_constant(num_options), - EX_CHECK_NO_CATCH); - - BasicBlock *no_handler = function()->CreateBlock("no_handler"); - SwitchInst *switchinst = builder()->CreateSwitch( - index, no_handler, num_options); - - for (int i = 0; i < num_options; i++) { - switchinst->addCase( - LLVMValue::jint_constant(i), - handler_for_exception(i)); - } - - builder()->SetInsertPoint(no_handler); -} - -BasicBlock* SharkTopLevelBlock::handler_for_exception(int index) { - SharkTopLevelBlock *successor = this->exception(index); - if (successor) { - successor->add_incoming(current_state()); - return successor->entry_block(); - } - else { - return make_trap( - exc_handler(index)->handler_bci(), - Deoptimization::make_trap_request( - Deoptimization::Reason_unhandled, - Deoptimization::Action_reinterpret)); - } -} - -void SharkTopLevelBlock::maybe_add_safepoint() { - if (current_state()->has_safepointed()) - return; - - BasicBlock *orig_block = builder()->GetInsertBlock(); - SharkState *orig_state = current_state()->copy(); - - BasicBlock *do_safepoint = function()->CreateBlock("do_safepoint"); - BasicBlock *safepointed = function()->CreateBlock("safepointed"); - - Value *state = builder()->CreateLoad( - builder()->CreateIntToPtr( - LLVMValue::intptr_constant( - (intptr_t) SafepointSynchronize::address_of_state()), - PointerType::getUnqual(SharkType::jint_type())), - "state"); - - builder()->CreateCondBr( - builder()->CreateICmpEQ( - state, - LLVMValue::jint_constant(SafepointSynchronize::_synchronizing)), - do_safepoint, safepointed); - - builder()->SetInsertPoint(do_safepoint); - call_vm(builder()->safepoint(), EX_CHECK_FULL); - BasicBlock *safepointed_block = builder()->GetInsertBlock(); - builder()->CreateBr(safepointed); - - builder()->SetInsertPoint(safepointed); - current_state()->merge(orig_state, orig_block, safepointed_block); - - current_state()->set_has_safepointed(true); -} - -void SharkTopLevelBlock::maybe_add_backedge_safepoint() { - if (current_state()->has_safepointed()) - return; - - for (int i = 0; i < num_successors(); i++) { - if (successor(i)->can_reach(this)) { - maybe_add_safepoint(); - break; - } - } -} - -bool SharkTopLevelBlock::can_reach(SharkTopLevelBlock* other) { - for (int i = 0; i < function()->block_count(); i++) - function()->block(i)->_can_reach_visited = false; - - return can_reach_helper(other); -} - -bool SharkTopLevelBlock::can_reach_helper(SharkTopLevelBlock* other) { - if (this == other) - return true; - - if (_can_reach_visited) - return false; - _can_reach_visited = true; - - if (!has_trap()) { - for (int i = 0; i < num_successors(); i++) { - if (successor(i)->can_reach_helper(other)) - return true; - } - } - - for (int i = 0; i < num_exceptions(); i++) { - SharkTopLevelBlock *handler = exception(i); - if (handler && handler->can_reach_helper(other)) - return true; - } - - return false; -} - -BasicBlock* SharkTopLevelBlock::make_trap(int trap_bci, int trap_request) { - BasicBlock *trap_block = function()->CreateBlock("trap"); - BasicBlock *orig_block = builder()->GetInsertBlock(); - builder()->SetInsertPoint(trap_block); - - int orig_bci = bci(); - iter()->force_bci(trap_bci); - - do_trap(trap_request); - - builder()->SetInsertPoint(orig_block); - iter()->force_bci(orig_bci); - - return trap_block; -} - -void SharkTopLevelBlock::do_trap(int trap_request) { - decache_for_trap(); - builder()->CreateRet( - builder()->CreateCall2( - builder()->uncommon_trap(), - thread(), - LLVMValue::jint_constant(trap_request))); -} - -void SharkTopLevelBlock::call_register_finalizer(Value *receiver) { - BasicBlock *orig_block = builder()->GetInsertBlock(); - SharkState *orig_state = current_state()->copy(); - - BasicBlock *do_call = function()->CreateBlock("has_finalizer"); - BasicBlock *done = function()->CreateBlock("done"); - - Value *klass = builder()->CreateValueOfStructEntry( - receiver, - in_ByteSize(oopDesc::klass_offset_in_bytes()), - SharkType::oop_type(), - "klass"); - - Value *access_flags = builder()->CreateValueOfStructEntry( - klass, - Klass::access_flags_offset(), - SharkType::jint_type(), - "access_flags"); - - builder()->CreateCondBr( - builder()->CreateICmpNE( - builder()->CreateAnd( - access_flags, - LLVMValue::jint_constant(JVM_ACC_HAS_FINALIZER)), - LLVMValue::jint_constant(0)), - do_call, done); - - builder()->SetInsertPoint(do_call); - call_vm(builder()->register_finalizer(), receiver, EX_CHECK_FULL); - BasicBlock *branch_block = builder()->GetInsertBlock(); - builder()->CreateBr(done); - - builder()->SetInsertPoint(done); - current_state()->merge(orig_state, orig_block, branch_block); -} - -void SharkTopLevelBlock::handle_return(BasicType type, Value* exception) { - assert (exception == NULL || type == T_VOID, "exception OR result, please"); - - if (num_monitors()) { - // Protect our exception across possible monitor release decaches - if (exception) - set_oop_tmp(exception); - - // We don't need to check for exceptions thrown here. If - // we're returning a value then we just carry on as normal: - // the caller will see the pending exception and handle it. - // If we're returning with an exception then that exception - // takes priority and the release_lock one will be ignored. - while (num_monitors()) - release_lock(EX_CHECK_NONE); - - // Reload the exception we're throwing - if (exception) - exception = get_oop_tmp(); - } - - if (exception) { - builder()->CreateStore(exception, pending_exception_address()); - } - - Value *result_addr = stack()->CreatePopFrame(type2size[type]); - if (type != T_VOID) { - builder()->CreateStore( - pop_result(type)->generic_value(), - builder()->CreateIntToPtr( - result_addr, - PointerType::getUnqual(SharkType::to_stackType(type)))); - } - - builder()->CreateRet(LLVMValue::jint_constant(0)); -} - -void SharkTopLevelBlock::do_arraylength() { - SharkValue *array = pop(); - check_null(array); - Value *length = builder()->CreateArrayLength(array->jarray_value()); - push(SharkValue::create_jint(length, false)); -} - -void SharkTopLevelBlock::do_aload(BasicType basic_type) { - SharkValue *index = pop(); - SharkValue *array = pop(); - - check_null(array); - check_bounds(array, index); - - Value *value = builder()->CreateLoad( - builder()->CreateArrayAddress( - array->jarray_value(), basic_type, index->jint_value())); - - Type *stack_type = SharkType::to_stackType(basic_type); - if (value->getType() != stack_type) - value = builder()->CreateIntCast(value, stack_type, basic_type != T_CHAR); - - switch (basic_type) { - case T_BYTE: - case T_CHAR: - case T_SHORT: - case T_INT: - push(SharkValue::create_jint(value, false)); - break; - - case T_LONG: - push(SharkValue::create_jlong(value, false)); - break; - - case T_FLOAT: - push(SharkValue::create_jfloat(value)); - break; - - case T_DOUBLE: - push(SharkValue::create_jdouble(value)); - break; - - case T_OBJECT: - // You might expect that array->type()->is_array_klass() would - // always be true, but it isn't. If ciTypeFlow detects that a - // value is always null then that value becomes an untyped null - // object. Shark doesn't presently support this, so a generic - // T_OBJECT is created. In this case we guess the type using - // the BasicType we were supplied. In reality the generated - // code will never be used, as the null value will be caught - // by the above null pointer check. - // http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=324 - push( - SharkValue::create_generic( - array->type()->is_array_klass() ? - ((ciArrayKlass *) array->type())->element_type() : - ciType::make(basic_type), - value, false)); - break; - - default: - tty->print_cr("Unhandled type %s", type2name(basic_type)); - ShouldNotReachHere(); - } -} - -void SharkTopLevelBlock::do_astore(BasicType basic_type) { - SharkValue *svalue = pop(); - SharkValue *index = pop(); - SharkValue *array = pop(); - - check_null(array); - check_bounds(array, index); - - Value *value; - switch (basic_type) { - case T_BYTE: - case T_CHAR: - case T_SHORT: - case T_INT: - value = svalue->jint_value(); - break; - - case T_LONG: - value = svalue->jlong_value(); - break; - - case T_FLOAT: - value = svalue->jfloat_value(); - break; - - case T_DOUBLE: - value = svalue->jdouble_value(); - break; - - case T_OBJECT: - value = svalue->jobject_value(); - // XXX assignability check - break; - - default: - tty->print_cr("Unhandled type %s", type2name(basic_type)); - ShouldNotReachHere(); - } - - Type *array_type = SharkType::to_arrayType(basic_type); - if (value->getType() != array_type) - value = builder()->CreateIntCast(value, array_type, basic_type != T_CHAR); - - Value *addr = builder()->CreateArrayAddress( - array->jarray_value(), basic_type, index->jint_value(), "addr"); - - builder()->CreateStore(value, addr); - - if (basic_type == T_OBJECT) // XXX or T_ARRAY? - builder()->CreateUpdateBarrierSet(oopDesc::bs(), addr); -} - -void SharkTopLevelBlock::do_return(BasicType type) { - if (target()->intrinsic_id() == vmIntrinsics::_Object_init) - call_register_finalizer(local(0)->jobject_value()); - maybe_add_safepoint(); - handle_return(type, NULL); -} - -void SharkTopLevelBlock::do_athrow() { - SharkValue *exception = pop(); - check_null(exception); - handle_exception(exception->jobject_value(), EX_CHECK_FULL); -} - -void SharkTopLevelBlock::do_goto() { - do_branch(ciTypeFlow::GOTO_TARGET); -} - -void SharkTopLevelBlock::do_jsr() { - push(SharkValue::address_constant(iter()->next_bci())); - do_branch(ciTypeFlow::GOTO_TARGET); -} - -void SharkTopLevelBlock::do_ret() { - assert(local(iter()->get_index())->address_value() == - successor(ciTypeFlow::GOTO_TARGET)->start(), "should be"); - do_branch(ciTypeFlow::GOTO_TARGET); -} - -// All propagation of state from one block to the next (via -// dest->add_incoming) is handled by these methods: -// do_branch -// do_if_helper -// do_switch -// handle_exception - -void SharkTopLevelBlock::do_branch(int successor_index) { - SharkTopLevelBlock *dest = successor(successor_index); - builder()->CreateBr(dest->entry_block()); - dest->add_incoming(current_state()); -} - -void SharkTopLevelBlock::do_if(ICmpInst::Predicate p, - SharkValue* b, - SharkValue* a) { - Value *llvm_a, *llvm_b; - if (a->is_jobject()) { - llvm_a = a->intptr_value(builder()); - llvm_b = b->intptr_value(builder()); - } - else { - llvm_a = a->jint_value(); - llvm_b = b->jint_value(); - } - do_if_helper(p, llvm_b, llvm_a, current_state(), current_state()); -} - -void SharkTopLevelBlock::do_if_helper(ICmpInst::Predicate p, - Value* b, - Value* a, - SharkState* if_taken_state, - SharkState* not_taken_state) { - SharkTopLevelBlock *if_taken = successor(ciTypeFlow::IF_TAKEN); - SharkTopLevelBlock *not_taken = successor(ciTypeFlow::IF_NOT_TAKEN); - - builder()->CreateCondBr( - builder()->CreateICmp(p, a, b), - if_taken->entry_block(), not_taken->entry_block()); - - if_taken->add_incoming(if_taken_state); - not_taken->add_incoming(not_taken_state); -} - -void SharkTopLevelBlock::do_switch() { - int len = switch_table_length(); - - SharkTopLevelBlock *dest_block = successor(ciTypeFlow::SWITCH_DEFAULT); - SwitchInst *switchinst = builder()->CreateSwitch( - pop()->jint_value(), dest_block->entry_block(), len); - dest_block->add_incoming(current_state()); - - for (int i = 0; i < len; i++) { - int dest_bci = switch_dest(i); - if (dest_bci != switch_default_dest()) { - dest_block = bci_successor(dest_bci); - switchinst->addCase( - LLVMValue::jint_constant(switch_key(i)), - dest_block->entry_block()); - dest_block->add_incoming(current_state()); - } - } -} - -ciMethod* SharkTopLevelBlock::improve_virtual_call(ciMethod* caller, - ciInstanceKlass* klass, - ciMethod* dest_method, - ciType* receiver_type) { - // If the method is obviously final then we are already done - if (dest_method->can_be_statically_bound()) - return dest_method; - - // Array methods are all inherited from Object and are monomorphic - if (receiver_type->is_array_klass() && - dest_method->holder() == java_lang_Object_klass()) - return dest_method; - - // This code can replace a virtual call with a direct call if this - // class is the only one in the entire set of loaded classes that - // implements this method. This makes the compiled code dependent - // on other classes that implement the method not being loaded, a - // condition which is enforced by the dependency tracker. If the - // dependency tracker determines a method has become invalid it - // will mark it for recompilation, causing running copies to be - // deoptimized. Shark currently can't deoptimize arbitrarily like - // that, so this optimization cannot be used. - // http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=481 - - // All other interesting cases are instance classes - if (!receiver_type->is_instance_klass()) - return NULL; - - // Attempt to improve the receiver - ciInstanceKlass* actual_receiver = klass; - ciInstanceKlass *improved_receiver = receiver_type->as_instance_klass(); - if (improved_receiver->is_loaded() && - improved_receiver->is_initialized() && - !improved_receiver->is_interface() && - improved_receiver->is_subtype_of(actual_receiver)) { - actual_receiver = improved_receiver; - } - - // Attempt to find a monomorphic target for this call using - // class heirachy analysis. - ciInstanceKlass *calling_klass = caller->holder(); - ciMethod* monomorphic_target = - dest_method->find_monomorphic_target(calling_klass, klass, actual_receiver); - if (monomorphic_target != NULL) { - assert(!monomorphic_target->is_abstract(), "shouldn't be"); - - function()->dependencies()->assert_unique_concrete_method(actual_receiver, monomorphic_target); - - // Opto has a bunch of type checking here that I don't - // understand. It's to inhibit casting in one direction, - // possibly because objects in Opto can have inexact - // types, but I can't even tell which direction it - // doesn't like. For now I'm going to block *any* cast. - if (monomorphic_target != dest_method) { - if (SharkPerformanceWarnings) { - warning("found monomorphic target, but inhibited cast:"); - tty->print(" dest_method = "); - dest_method->print_short_name(tty); - tty->cr(); - tty->print(" monomorphic_target = "); - monomorphic_target->print_short_name(tty); - tty->cr(); - } - monomorphic_target = NULL; - } - } - - // Replace the virtual call with a direct one. This makes - // us dependent on that target method not getting overridden - // by dynamic class loading. - if (monomorphic_target != NULL) { - dependencies()->assert_unique_concrete_method( - actual_receiver, monomorphic_target); - return monomorphic_target; - } - - // Because Opto distinguishes exact types from inexact ones - // it can perform a further optimization to replace calls - // with non-monomorphic targets if the receiver has an exact - // type. We don't mark types this way, so we can't do this. - - - return NULL; -} - -Value *SharkTopLevelBlock::get_direct_callee(ciMethod* method) { - return builder()->CreateBitCast( - builder()->CreateInlineMetadata(method, SharkType::Method_type()), - SharkType::Method_type(), - "callee"); -} - -Value *SharkTopLevelBlock::get_virtual_callee(SharkValue* receiver, - int vtable_index) { - Value *klass = builder()->CreateValueOfStructEntry( - receiver->jobject_value(), - in_ByteSize(oopDesc::klass_offset_in_bytes()), - SharkType::oop_type(), - "klass"); - - return builder()->CreateLoad( - builder()->CreateArrayAddress( - klass, - SharkType::Method_type(), - vtableEntry::size_in_bytes(), - Klass::vtable_start_offset(), - LLVMValue::intptr_constant(vtable_index)), - "callee"); -} - -Value* SharkTopLevelBlock::get_interface_callee(SharkValue *receiver, - ciMethod* method) { - BasicBlock *loop = function()->CreateBlock("loop"); - BasicBlock *got_null = function()->CreateBlock("got_null"); - BasicBlock *not_null = function()->CreateBlock("not_null"); - BasicBlock *next = function()->CreateBlock("next"); - BasicBlock *got_entry = function()->CreateBlock("got_entry"); - - // Locate the receiver's itable - Value *object_klass = builder()->CreateValueOfStructEntry( - receiver->jobject_value(), in_ByteSize(oopDesc::klass_offset_in_bytes()), - SharkType::klass_type(), - "object_klass"); - - Value *vtable_start = builder()->CreateAdd( - builder()->CreatePtrToInt(object_klass, SharkType::intptr_type()), - LLVMValue::intptr_constant( - in_bytes(Klass::vtable_start_offset())), - "vtable_start"); - - Value *vtable_length = builder()->CreateValueOfStructEntry( - object_klass, - Klass::vtable_length_offset(), - SharkType::jint_type(), - "vtable_length"); - vtable_length = - builder()->CreateIntCast(vtable_length, SharkType::intptr_type(), false); - - bool needs_aligning = HeapWordsPerLong > 1; - Value *itable_start = builder()->CreateAdd( - vtable_start, - builder()->CreateShl( - vtable_length, - LLVMValue::intptr_constant(exact_log2(vtableEntry::size_in_bytes()))), - needs_aligning ? "" : "itable_start"); - if (needs_aligning) { - itable_start = builder()->CreateAnd( - builder()->CreateAdd( - itable_start, LLVMValue::intptr_constant(BytesPerLong - 1)), - LLVMValue::intptr_constant(~(BytesPerLong - 1)), - "itable_start"); - } - - // Locate this interface's entry in the table - Value *iklass = builder()->CreateInlineMetadata(method->holder(), SharkType::klass_type()); - BasicBlock *loop_entry = builder()->GetInsertBlock(); - builder()->CreateBr(loop); - builder()->SetInsertPoint(loop); - PHINode *itable_entry_addr = builder()->CreatePHI( - SharkType::intptr_type(), 0, "itable_entry_addr"); - itable_entry_addr->addIncoming(itable_start, loop_entry); - - Value *itable_entry = builder()->CreateIntToPtr( - itable_entry_addr, SharkType::itableOffsetEntry_type(), "itable_entry"); - - Value *itable_iklass = builder()->CreateValueOfStructEntry( - itable_entry, - in_ByteSize(itableOffsetEntry::interface_offset_in_bytes()), - SharkType::klass_type(), - "itable_iklass"); - - builder()->CreateCondBr( - builder()->CreateICmpEQ(itable_iklass, LLVMValue::nullKlass()), - got_null, not_null); - - // A null entry means that the class doesn't implement the - // interface, and wasn't the same as the class checked when - // the interface was resolved. - builder()->SetInsertPoint(got_null); - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); - - builder()->SetInsertPoint(not_null); - builder()->CreateCondBr( - builder()->CreateICmpEQ(itable_iklass, iklass), - got_entry, next); - - builder()->SetInsertPoint(next); - Value *next_entry = builder()->CreateAdd( - itable_entry_addr, - LLVMValue::intptr_constant(itableOffsetEntry::size() * wordSize)); - builder()->CreateBr(loop); - itable_entry_addr->addIncoming(next_entry, next); - - // Locate the method pointer - builder()->SetInsertPoint(got_entry); - Value *offset = builder()->CreateValueOfStructEntry( - itable_entry, - in_ByteSize(itableOffsetEntry::offset_offset_in_bytes()), - SharkType::jint_type(), - "offset"); - offset = - builder()->CreateIntCast(offset, SharkType::intptr_type(), false); - - return builder()->CreateLoad( - builder()->CreateIntToPtr( - builder()->CreateAdd( - builder()->CreateAdd( - builder()->CreateAdd( - builder()->CreatePtrToInt( - object_klass, SharkType::intptr_type()), - offset), - LLVMValue::intptr_constant( - method->itable_index() * itableMethodEntry::size() * wordSize)), - LLVMValue::intptr_constant( - itableMethodEntry::method_offset_in_bytes())), - PointerType::getUnqual(SharkType::Method_type())), - "callee"); -} - -void SharkTopLevelBlock::do_call() { - // Set frequently used booleans - bool is_static = bc() == Bytecodes::_invokestatic; - bool is_virtual = bc() == Bytecodes::_invokevirtual; - bool is_interface = bc() == Bytecodes::_invokeinterface; - - // Find the method being called - bool will_link; - ciSignature* sig; - ciMethod *dest_method = iter()->get_method(will_link, &sig); - - assert(will_link, "typeflow responsibility"); - assert(dest_method->is_static() == is_static, "must match bc"); - - // Find the class of the method being called. Note - // that the superclass check in the second assertion - // is to cope with a hole in the spec that allows for - // invokeinterface instructions where the resolved - // method is a virtual method in java.lang.Object. - // javac doesn't generate code like that, but there's - // no reason a compliant Java compiler might not. - ciInstanceKlass *holder_klass = dest_method->holder(); - assert(holder_klass->is_loaded(), "scan_for_traps responsibility"); - assert(holder_klass->is_interface() || - holder_klass->super() == NULL || - !is_interface, "must match bc"); - - bool is_forced_virtual = is_interface && holder_klass == java_lang_Object_klass(); - - ciKlass *holder = iter()->get_declared_method_holder(); - ciInstanceKlass *klass = - ciEnv::get_instance_klass_for_declared_method_holder(holder); - - if (is_forced_virtual) { - klass = java_lang_Object_klass(); - } - - // Find the receiver in the stack. We do this before - // trying to inline because the inliner can only use - // zero-checked values, not being able to perform the - // check itself. - SharkValue *receiver = NULL; - if (!is_static) { - receiver = xstack(dest_method->arg_size() - 1); - check_null(receiver); - } - - // Try to improve non-direct calls - bool call_is_virtual = is_virtual || is_interface; - ciMethod *call_method = dest_method; - if (call_is_virtual) { - ciMethod *optimized_method = improve_virtual_call( - target(), klass, dest_method, receiver->type()); - if (optimized_method) { - call_method = optimized_method; - call_is_virtual = false; - } - } - - // Try to inline the call - if (!call_is_virtual) { - if (SharkInliner::attempt_inline(call_method, current_state())) { - return; - } - } - - // Find the method we are calling - Value *callee; - if (call_is_virtual) { - if (is_virtual || is_forced_virtual) { - assert(klass->is_linked(), "scan_for_traps responsibility"); - int vtable_index = call_method->resolve_vtable_index( - target()->holder(), klass); - assert(vtable_index >= 0, "should be"); - callee = get_virtual_callee(receiver, vtable_index); - } - else { - assert(is_interface, "should be"); - callee = get_interface_callee(receiver, call_method); - } - } - else { - callee = get_direct_callee(call_method); - } - - // Load the SharkEntry from the callee - Value *base_pc = builder()->CreateValueOfStructEntry( - callee, Method::from_interpreted_offset(), - SharkType::intptr_type(), - "base_pc"); - - // Load the entry point from the SharkEntry - Value *entry_point = builder()->CreateLoad( - builder()->CreateIntToPtr( - builder()->CreateAdd( - base_pc, - LLVMValue::intptr_constant(in_bytes(ZeroEntry::entry_point_offset()))), - PointerType::getUnqual( - PointerType::getUnqual(SharkType::entry_point_type()))), - "entry_point"); - - // Make the call - decache_for_Java_call(call_method); - Value *deoptimized_frames = builder()->CreateCall3( - entry_point, callee, base_pc, thread()); - - // If the callee got deoptimized then reexecute in the interpreter - BasicBlock *reexecute = function()->CreateBlock("reexecute"); - BasicBlock *call_completed = function()->CreateBlock("call_completed"); - builder()->CreateCondBr( - builder()->CreateICmpNE(deoptimized_frames, LLVMValue::jint_constant(0)), - reexecute, call_completed); - - builder()->SetInsertPoint(reexecute); - builder()->CreateCall2( - builder()->deoptimized_entry_point(), - builder()->CreateSub(deoptimized_frames, LLVMValue::jint_constant(1)), - thread()); - builder()->CreateBr(call_completed); - - // Cache after the call - builder()->SetInsertPoint(call_completed); - cache_after_Java_call(call_method); - - // Check for pending exceptions - check_pending_exception(EX_CHECK_FULL); - - // Mark that a safepoint check has occurred - current_state()->set_has_safepointed(true); -} - -bool SharkTopLevelBlock::static_subtype_check(ciKlass* check_klass, - ciKlass* object_klass) { - // If the class we're checking against is java.lang.Object - // then this is a no brainer. Apparently this can happen - // in reflective code... - if (check_klass == java_lang_Object_klass()) - return true; - - // Perform a subtype check. NB in opto's code for this - // (GraphKit::static_subtype_check) it says that static - // interface types cannot be trusted, and if opto can't - // trust them then I assume we can't either. - if (object_klass->is_loaded() && !object_klass->is_interface()) { - if (object_klass == check_klass) - return true; - - if (check_klass->is_loaded() && object_klass->is_subtype_of(check_klass)) - return true; - } - - return false; -} - -void SharkTopLevelBlock::do_instance_check() { - // Get the class we're checking against - bool will_link; - ciKlass *check_klass = iter()->get_klass(will_link); - - // Get the class of the object we're checking - ciKlass *object_klass = xstack(0)->type()->as_klass(); - - // Can we optimize this check away? - if (static_subtype_check(check_klass, object_klass)) { - if (bc() == Bytecodes::_instanceof) { - pop(); - push(SharkValue::jint_constant(1)); - } - return; - } - - // Need to check this one at runtime - if (will_link) - do_full_instance_check(check_klass); - else - do_trapping_instance_check(check_klass); -} - -bool SharkTopLevelBlock::maybe_do_instanceof_if() { - // Get the class we're checking against - bool will_link; - ciKlass *check_klass = iter()->get_klass(will_link); - - // If the class is unloaded then the instanceof - // cannot possibly succeed. - if (!will_link) - return false; - - // Keep a copy of the object we're checking - SharkValue *old_object = xstack(0); - - // Get the class of the object we're checking - ciKlass *object_klass = old_object->type()->as_klass(); - - // If the instanceof can be optimized away at compile time - // then any subsequent checkcasts will be too so we handle - // it normally. - if (static_subtype_check(check_klass, object_klass)) - return false; - - // Perform the instance check - do_full_instance_check(check_klass); - Value *result = pop()->jint_value(); - - // Create the casted object - SharkValue *new_object = SharkValue::create_generic( - check_klass, old_object->jobject_value(), old_object->zero_checked()); - - // Create two copies of the current state, one with the - // original object and one with all instances of the - // original object replaced with the new, casted object. - SharkState *new_state = current_state(); - SharkState *old_state = new_state->copy(); - new_state->replace_all(old_object, new_object); - - // Perform the check-and-branch - switch (iter()->next_bc()) { - case Bytecodes::_ifeq: - // branch if not an instance - do_if_helper( - ICmpInst::ICMP_EQ, - LLVMValue::jint_constant(0), result, - old_state, new_state); - break; - - case Bytecodes::_ifne: - // branch if an instance - do_if_helper( - ICmpInst::ICMP_NE, - LLVMValue::jint_constant(0), result, - new_state, old_state); - break; - - default: - ShouldNotReachHere(); - } - - return true; -} - -void SharkTopLevelBlock::do_full_instance_check(ciKlass* klass) { - BasicBlock *not_null = function()->CreateBlock("not_null"); - BasicBlock *subtype_check = function()->CreateBlock("subtype_check"); - BasicBlock *is_instance = function()->CreateBlock("is_instance"); - BasicBlock *not_instance = function()->CreateBlock("not_instance"); - BasicBlock *merge1 = function()->CreateBlock("merge1"); - BasicBlock *merge2 = function()->CreateBlock("merge2"); - - enum InstanceCheckStates { - IC_IS_NULL, - IC_IS_INSTANCE, - IC_NOT_INSTANCE, - }; - - // Pop the object off the stack - Value *object = pop()->jobject_value(); - - // Null objects aren't instances of anything - builder()->CreateCondBr( - builder()->CreateICmpEQ(object, LLVMValue::null()), - merge2, not_null); - BasicBlock *null_block = builder()->GetInsertBlock(); - - // Get the class we're checking against - builder()->SetInsertPoint(not_null); - Value *check_klass = builder()->CreateInlineMetadata(klass, SharkType::klass_type()); - - // Get the class of the object being tested - Value *object_klass = builder()->CreateValueOfStructEntry( - object, in_ByteSize(oopDesc::klass_offset_in_bytes()), - SharkType::klass_type(), - "object_klass"); - - // Perform the check - builder()->CreateCondBr( - builder()->CreateICmpEQ(check_klass, object_klass), - is_instance, subtype_check); - - builder()->SetInsertPoint(subtype_check); - builder()->CreateCondBr( - builder()->CreateICmpNE( - builder()->CreateCall2( - builder()->is_subtype_of(), check_klass, object_klass), - LLVMValue::jbyte_constant(0)), - is_instance, not_instance); - - builder()->SetInsertPoint(is_instance); - builder()->CreateBr(merge1); - - builder()->SetInsertPoint(not_instance); - builder()->CreateBr(merge1); - - // First merge - builder()->SetInsertPoint(merge1); - PHINode *nonnull_result = builder()->CreatePHI( - SharkType::jint_type(), 0, "nonnull_result"); - nonnull_result->addIncoming( - LLVMValue::jint_constant(IC_IS_INSTANCE), is_instance); - nonnull_result->addIncoming( - LLVMValue::jint_constant(IC_NOT_INSTANCE), not_instance); - BasicBlock *nonnull_block = builder()->GetInsertBlock(); - builder()->CreateBr(merge2); - - // Second merge - builder()->SetInsertPoint(merge2); - PHINode *result = builder()->CreatePHI( - SharkType::jint_type(), 0, "result"); - result->addIncoming(LLVMValue::jint_constant(IC_IS_NULL), null_block); - result->addIncoming(nonnull_result, nonnull_block); - - // Handle the result - if (bc() == Bytecodes::_checkcast) { - BasicBlock *failure = function()->CreateBlock("failure"); - BasicBlock *success = function()->CreateBlock("success"); - - builder()->CreateCondBr( - builder()->CreateICmpNE( - result, LLVMValue::jint_constant(IC_NOT_INSTANCE)), - success, failure); - - builder()->SetInsertPoint(failure); - SharkState *saved_state = current_state()->copy(); - - call_vm( - builder()->throw_ClassCastException(), - builder()->CreateIntToPtr( - LLVMValue::intptr_constant((intptr_t) __FILE__), - PointerType::getUnqual(SharkType::jbyte_type())), - LLVMValue::jint_constant(__LINE__), - EX_CHECK_NONE); - - Value *pending_exception = get_pending_exception(); - clear_pending_exception(); - handle_exception(pending_exception, EX_CHECK_FULL); - - set_current_state(saved_state); - builder()->SetInsertPoint(success); - push(SharkValue::create_generic(klass, object, false)); - } - else { - push( - SharkValue::create_jint( - builder()->CreateIntCast( - builder()->CreateICmpEQ( - result, LLVMValue::jint_constant(IC_IS_INSTANCE)), - SharkType::jint_type(), false), false)); - } -} - -void SharkTopLevelBlock::do_trapping_instance_check(ciKlass* klass) { - BasicBlock *not_null = function()->CreateBlock("not_null"); - BasicBlock *is_null = function()->CreateBlock("null"); - - // Leave the object on the stack so it's there if we trap - builder()->CreateCondBr( - builder()->CreateICmpEQ(xstack(0)->jobject_value(), LLVMValue::null()), - is_null, not_null); - SharkState *saved_state = current_state()->copy(); - - // If it's not null then we need to trap - builder()->SetInsertPoint(not_null); - set_current_state(saved_state->copy()); - do_trap( - Deoptimization::make_trap_request( - Deoptimization::Reason_uninitialized, - Deoptimization::Action_reinterpret)); - - // If it's null then we're ok - builder()->SetInsertPoint(is_null); - set_current_state(saved_state); - if (bc() == Bytecodes::_checkcast) { - push(SharkValue::create_generic(klass, pop()->jobject_value(), false)); - } - else { - pop(); - push(SharkValue::jint_constant(0)); - } -} - -void SharkTopLevelBlock::do_new() { - bool will_link; - ciInstanceKlass* klass = iter()->get_klass(will_link)->as_instance_klass(); - assert(will_link, "typeflow responsibility"); - - BasicBlock *got_tlab = NULL; - BasicBlock *heap_alloc = NULL; - BasicBlock *retry = NULL; - BasicBlock *got_heap = NULL; - BasicBlock *initialize = NULL; - BasicBlock *got_fast = NULL; - BasicBlock *slow_alloc_and_init = NULL; - BasicBlock *got_slow = NULL; - BasicBlock *push_object = NULL; - - SharkState *fast_state = NULL; - - Value *tlab_object = NULL; - Value *heap_object = NULL; - Value *fast_object = NULL; - Value *slow_object = NULL; - Value *object = NULL; - - // The fast path - if (!Klass::layout_helper_needs_slow_path(klass->layout_helper())) { - if (UseTLAB) { - got_tlab = function()->CreateBlock("got_tlab"); - heap_alloc = function()->CreateBlock("heap_alloc"); - } - retry = function()->CreateBlock("retry"); - got_heap = function()->CreateBlock("got_heap"); - initialize = function()->CreateBlock("initialize"); - slow_alloc_and_init = function()->CreateBlock("slow_alloc_and_init"); - push_object = function()->CreateBlock("push_object"); - - size_t size_in_bytes = klass->size_helper() << LogHeapWordSize; - - // Thread local allocation - if (UseTLAB) { - Value *top_addr = builder()->CreateAddressOfStructEntry( - thread(), Thread::tlab_top_offset(), - PointerType::getUnqual(SharkType::intptr_type()), - "top_addr"); - - Value *end = builder()->CreateValueOfStructEntry( - thread(), Thread::tlab_end_offset(), - SharkType::intptr_type(), - "end"); - - Value *old_top = builder()->CreateLoad(top_addr, "old_top"); - Value *new_top = builder()->CreateAdd( - old_top, LLVMValue::intptr_constant(size_in_bytes)); - - builder()->CreateCondBr( - builder()->CreateICmpULE(new_top, end), - got_tlab, heap_alloc); - - builder()->SetInsertPoint(got_tlab); - tlab_object = builder()->CreateIntToPtr( - old_top, SharkType::oop_type(), "tlab_object"); - - builder()->CreateStore(new_top, top_addr); - builder()->CreateBr(initialize); - - builder()->SetInsertPoint(heap_alloc); - } - - // Heap allocation - Value *top_addr = builder()->CreateIntToPtr( - LLVMValue::intptr_constant((intptr_t) Universe::heap()->top_addr()), - PointerType::getUnqual(SharkType::intptr_type()), - "top_addr"); - - Value *end = builder()->CreateLoad( - builder()->CreateIntToPtr( - LLVMValue::intptr_constant((intptr_t) Universe::heap()->end_addr()), - PointerType::getUnqual(SharkType::intptr_type())), - "end"); - - builder()->CreateBr(retry); - builder()->SetInsertPoint(retry); - - Value *old_top = builder()->CreateLoad(top_addr, "top"); - Value *new_top = builder()->CreateAdd( - old_top, LLVMValue::intptr_constant(size_in_bytes)); - - builder()->CreateCondBr( - builder()->CreateICmpULE(new_top, end), - got_heap, slow_alloc_and_init); - - builder()->SetInsertPoint(got_heap); - heap_object = builder()->CreateIntToPtr( - old_top, SharkType::oop_type(), "heap_object"); - - Value *check = builder()->CreateAtomicCmpXchg(top_addr, old_top, new_top, llvm::SequentiallyConsistent); - builder()->CreateCondBr( - builder()->CreateICmpEQ(old_top, check), - initialize, retry); - - // Initialize the object - builder()->SetInsertPoint(initialize); - if (tlab_object) { - PHINode *phi = builder()->CreatePHI( - SharkType::oop_type(), 0, "fast_object"); - phi->addIncoming(tlab_object, got_tlab); - phi->addIncoming(heap_object, got_heap); - fast_object = phi; - } - else { - fast_object = heap_object; - } - - builder()->CreateMemset( - builder()->CreateBitCast( - fast_object, PointerType::getUnqual(SharkType::jbyte_type())), - LLVMValue::jbyte_constant(0), - LLVMValue::jint_constant(size_in_bytes), - LLVMValue::jint_constant(HeapWordSize)); - - Value *mark_addr = builder()->CreateAddressOfStructEntry( - fast_object, in_ByteSize(oopDesc::mark_offset_in_bytes()), - PointerType::getUnqual(SharkType::intptr_type()), - "mark_addr"); - - Value *klass_addr = builder()->CreateAddressOfStructEntry( - fast_object, in_ByteSize(oopDesc::klass_offset_in_bytes()), - PointerType::getUnqual(SharkType::klass_type()), - "klass_addr"); - - // Set the mark - intptr_t mark; - if (UseBiasedLocking) { - Unimplemented(); - } - else { - mark = (intptr_t) markOopDesc::prototype(); - } - builder()->CreateStore(LLVMValue::intptr_constant(mark), mark_addr); - - // Set the class - Value *rtklass = builder()->CreateInlineMetadata(klass, SharkType::klass_type()); - builder()->CreateStore(rtklass, klass_addr); - got_fast = builder()->GetInsertBlock(); - - builder()->CreateBr(push_object); - builder()->SetInsertPoint(slow_alloc_and_init); - fast_state = current_state()->copy(); - } - - // The slow path - call_vm( - builder()->new_instance(), - LLVMValue::jint_constant(iter()->get_klass_index()), - EX_CHECK_FULL); - slow_object = get_vm_result(); - got_slow = builder()->GetInsertBlock(); - - // Push the object - if (push_object) { - builder()->CreateBr(push_object); - builder()->SetInsertPoint(push_object); - } - if (fast_object) { - PHINode *phi = builder()->CreatePHI(SharkType::oop_type(), 0, "object"); - phi->addIncoming(fast_object, got_fast); - phi->addIncoming(slow_object, got_slow); - object = phi; - current_state()->merge(fast_state, got_fast, got_slow); - } - else { - object = slow_object; - } - - push(SharkValue::create_jobject(object, true)); -} - -void SharkTopLevelBlock::do_newarray() { - BasicType type = (BasicType) iter()->get_index(); - - call_vm( - builder()->newarray(), - LLVMValue::jint_constant(type), - pop()->jint_value(), - EX_CHECK_FULL); - - ciArrayKlass *array_klass = ciArrayKlass::make(ciType::make(type)); - push(SharkValue::create_generic(array_klass, get_vm_result(), true)); -} - -void SharkTopLevelBlock::do_anewarray() { - bool will_link; - ciKlass *klass = iter()->get_klass(will_link); - assert(will_link, "typeflow responsibility"); - - ciObjArrayKlass *array_klass = ciObjArrayKlass::make(klass); - if (!array_klass->is_loaded()) { - Unimplemented(); - } - - call_vm( - builder()->anewarray(), - LLVMValue::jint_constant(iter()->get_klass_index()), - pop()->jint_value(), - EX_CHECK_FULL); - - push(SharkValue::create_generic(array_klass, get_vm_result(), true)); -} - -void SharkTopLevelBlock::do_multianewarray() { - bool will_link; - ciArrayKlass *array_klass = iter()->get_klass(will_link)->as_array_klass(); - assert(will_link, "typeflow responsibility"); - - // The dimensions are stack values, so we use their slots for the - // dimensions array. Note that we are storing them in the reverse - // of normal stack order. - int ndims = iter()->get_dimensions(); - - Value *dimensions = stack()->slot_addr( - stack()->stack_slots_offset() + max_stack() - xstack_depth(), - ArrayType::get(SharkType::jint_type(), ndims), - "dimensions"); - - for (int i = 0; i < ndims; i++) { - builder()->CreateStore( - xstack(ndims - 1 - i)->jint_value(), - builder()->CreateStructGEP(dimensions, i)); - } - - call_vm( - builder()->multianewarray(), - LLVMValue::jint_constant(iter()->get_klass_index()), - LLVMValue::jint_constant(ndims), - builder()->CreateStructGEP(dimensions, 0), - EX_CHECK_FULL); - - // Now we can pop the dimensions off the stack - for (int i = 0; i < ndims; i++) - pop(); - - push(SharkValue::create_generic(array_klass, get_vm_result(), true)); -} - -void SharkTopLevelBlock::acquire_method_lock() { - Value *lockee; - if (target()->is_static()) { - lockee = builder()->CreateInlineOop(target()->holder()->java_mirror()); - } - else - lockee = local(0)->jobject_value(); - - iter()->force_bci(start()); // for the decache in acquire_lock - acquire_lock(lockee, EX_CHECK_NO_CATCH); -} - -void SharkTopLevelBlock::do_monitorenter() { - SharkValue *lockee = pop(); - check_null(lockee); - acquire_lock(lockee->jobject_value(), EX_CHECK_FULL); -} - -void SharkTopLevelBlock::do_monitorexit() { - pop(); // don't need this (monitors are block structured) - release_lock(EX_CHECK_NO_CATCH); -} - -void SharkTopLevelBlock::acquire_lock(Value *lockee, int exception_action) { - BasicBlock *try_recursive = function()->CreateBlock("try_recursive"); - BasicBlock *got_recursive = function()->CreateBlock("got_recursive"); - BasicBlock *not_recursive = function()->CreateBlock("not_recursive"); - BasicBlock *acquired_fast = function()->CreateBlock("acquired_fast"); - BasicBlock *lock_acquired = function()->CreateBlock("lock_acquired"); - - int monitor = num_monitors(); - Value *monitor_addr = stack()->monitor_addr(monitor); - Value *monitor_object_addr = stack()->monitor_object_addr(monitor); - Value *monitor_header_addr = stack()->monitor_header_addr(monitor); - - // Store the object and mark the slot as live - builder()->CreateStore(lockee, monitor_object_addr); - set_num_monitors(monitor + 1); - - // Try a simple lock - Value *mark_addr = builder()->CreateAddressOfStructEntry( - lockee, in_ByteSize(oopDesc::mark_offset_in_bytes()), - PointerType::getUnqual(SharkType::intptr_type()), - "mark_addr"); - - Value *mark = builder()->CreateLoad(mark_addr, "mark"); - Value *disp = builder()->CreateOr( - mark, LLVMValue::intptr_constant(markOopDesc::unlocked_value), "disp"); - builder()->CreateStore(disp, monitor_header_addr); - - Value *lock = builder()->CreatePtrToInt( - monitor_header_addr, SharkType::intptr_type()); - Value *check = builder()->CreateAtomicCmpXchg(mark_addr, disp, lock, llvm::Acquire); - builder()->CreateCondBr( - builder()->CreateICmpEQ(disp, check), - acquired_fast, try_recursive); - - // Locking failed, but maybe this thread already owns it - builder()->SetInsertPoint(try_recursive); - Value *addr = builder()->CreateAnd( - disp, - LLVMValue::intptr_constant(~markOopDesc::lock_mask_in_place)); - - // NB we use the entire stack, but JavaThread::is_lock_owned() - // uses a more limited range. I don't think it hurts though... - Value *stack_limit = builder()->CreateValueOfStructEntry( - thread(), Thread::stack_base_offset(), - SharkType::intptr_type(), - "stack_limit"); - - assert(sizeof(size_t) == sizeof(intptr_t), "should be"); - Value *stack_size = builder()->CreateValueOfStructEntry( - thread(), Thread::stack_size_offset(), - SharkType::intptr_type(), - "stack_size"); - - Value *stack_start = - builder()->CreateSub(stack_limit, stack_size, "stack_start"); - - builder()->CreateCondBr( - builder()->CreateAnd( - builder()->CreateICmpUGE(addr, stack_start), - builder()->CreateICmpULT(addr, stack_limit)), - got_recursive, not_recursive); - - builder()->SetInsertPoint(got_recursive); - builder()->CreateStore(LLVMValue::intptr_constant(0), monitor_header_addr); - builder()->CreateBr(acquired_fast); - - // Create an edge for the state merge - builder()->SetInsertPoint(acquired_fast); - SharkState *fast_state = current_state()->copy(); - builder()->CreateBr(lock_acquired); - - // It's not a recursive case so we need to drop into the runtime - builder()->SetInsertPoint(not_recursive); - call_vm( - builder()->monitorenter(), monitor_addr, - exception_action | EAM_MONITOR_FUDGE); - BasicBlock *acquired_slow = builder()->GetInsertBlock(); - builder()->CreateBr(lock_acquired); - - // All done - builder()->SetInsertPoint(lock_acquired); - current_state()->merge(fast_state, acquired_fast, acquired_slow); -} - -void SharkTopLevelBlock::release_lock(int exception_action) { - BasicBlock *not_recursive = function()->CreateBlock("not_recursive"); - BasicBlock *released_fast = function()->CreateBlock("released_fast"); - BasicBlock *slow_path = function()->CreateBlock("slow_path"); - BasicBlock *lock_released = function()->CreateBlock("lock_released"); - - int monitor = num_monitors() - 1; - Value *monitor_addr = stack()->monitor_addr(monitor); - Value *monitor_object_addr = stack()->monitor_object_addr(monitor); - Value *monitor_header_addr = stack()->monitor_header_addr(monitor); - - // If it is recursive then we're already done - Value *disp = builder()->CreateLoad(monitor_header_addr); - builder()->CreateCondBr( - builder()->CreateICmpEQ(disp, LLVMValue::intptr_constant(0)), - released_fast, not_recursive); - - // Try a simple unlock - builder()->SetInsertPoint(not_recursive); - - Value *lock = builder()->CreatePtrToInt( - monitor_header_addr, SharkType::intptr_type()); - - Value *lockee = builder()->CreateLoad(monitor_object_addr); - - Value *mark_addr = builder()->CreateAddressOfStructEntry( - lockee, in_ByteSize(oopDesc::mark_offset_in_bytes()), - PointerType::getUnqual(SharkType::intptr_type()), - "mark_addr"); - - Value *check = builder()->CreateAtomicCmpXchg(mark_addr, lock, disp, llvm::Release); - builder()->CreateCondBr( - builder()->CreateICmpEQ(lock, check), - released_fast, slow_path); - - // Create an edge for the state merge - builder()->SetInsertPoint(released_fast); - SharkState *fast_state = current_state()->copy(); - builder()->CreateBr(lock_released); - - // Need to drop into the runtime to release this one - builder()->SetInsertPoint(slow_path); - call_vm(builder()->monitorexit(), monitor_addr, exception_action); - BasicBlock *released_slow = builder()->GetInsertBlock(); - builder()->CreateBr(lock_released); - - // All done - builder()->SetInsertPoint(lock_released); - current_state()->merge(fast_state, released_fast, released_slow); - - // The object slot is now dead - set_num_monitors(monitor); -} diff --git a/src/hotspot/share/shark/sharkTopLevelBlock.hpp b/src/hotspot/share/shark/sharkTopLevelBlock.hpp deleted file mode 100644 index a1306f30cb5..00000000000 --- a/src/hotspot/share/shark/sharkTopLevelBlock.hpp +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKTOPLEVELBLOCK_HPP -#define SHARE_VM_SHARK_SHARKTOPLEVELBLOCK_HPP - -#include "ci/ciStreams.hpp" -#include "ci/ciType.hpp" -#include "ci/ciTypeFlow.hpp" -#include "interpreter/bytecodes.hpp" -#include "memory/allocation.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkBlock.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkFunction.hpp" -#include "shark/sharkState.hpp" -#include "shark/sharkValue.hpp" - -class SharkTopLevelBlock : public SharkBlock { - public: - SharkTopLevelBlock(SharkFunction* function, ciTypeFlow::Block* ciblock) - : SharkBlock(function), - _function(function), - _ciblock(ciblock), - _entered(false), - _has_trap(false), - _needs_phis(false), - _entry_state(NULL), - _entry_block(NULL) {} - - private: - SharkFunction* _function; - ciTypeFlow::Block* _ciblock; - - public: - SharkFunction* function() const { - return _function; - } - ciTypeFlow::Block* ciblock() const { - return _ciblock; - } - - // Function properties - public: - SharkStack* stack() const { - return function()->stack(); - } - - // Typeflow properties - public: - int index() const { - return ciblock()->pre_order(); - } - bool is_backedge_copy() const { - return ciblock()->is_backedge_copy(); - } - int stack_depth_at_entry() const { - return ciblock()->stack_size(); - } - ciType* local_type_at_entry(int index) const { - return ciblock()->local_type_at(index); - } - ciType* stack_type_at_entry(int slot) const { - return ciblock()->stack_type_at(slot); - } - int start() const { - return ciblock()->start(); - } - int limit() const { - return ciblock()->limit(); - } - bool falls_through() const { - return ciblock()->control() == ciBlock::fall_through_bci; - } - int num_successors() const { - return ciblock()->successors()->length(); - } - SharkTopLevelBlock* successor(int index) const { - return function()->block(ciblock()->successors()->at(index)->pre_order()); - } - SharkTopLevelBlock* bci_successor(int bci) const; - - // Exceptions - private: - GrowableArray* _exc_handlers; - GrowableArray* _exceptions; - - private: - void compute_exceptions(); - - private: - int num_exceptions() const { - return _exc_handlers->length(); - } - ciExceptionHandler* exc_handler(int index) const { - return _exc_handlers->at(index); - } - SharkTopLevelBlock* exception(int index) const { - return _exceptions->at(index); - } - - // Traps - private: - bool _has_trap; - int _trap_request; - int _trap_bci; - - void set_trap(int trap_request, int trap_bci) { - assert(!has_trap(), "shouldn't have"); - _has_trap = true; - _trap_request = trap_request; - _trap_bci = trap_bci; - } - - private: - bool has_trap() { - return _has_trap; - } - int trap_request() { - assert(has_trap(), "should have"); - return _trap_request; - } - int trap_bci() { - assert(has_trap(), "should have"); - return _trap_bci; - } - - private: - void scan_for_traps(); - - private: - bool static_field_ok_in_clinit(ciField* field); - - // Entry state - private: - bool _entered; - bool _needs_phis; - - public: - bool entered() const { - return _entered; - } - bool needs_phis() const { - return _needs_phis; - } - - private: - void enter(SharkTopLevelBlock* predecessor, bool is_exception); - - public: - void enter() { - enter(NULL, false); - } - - private: - SharkState* _entry_state; - - private: - SharkState* entry_state(); - - private: - llvm::BasicBlock* _entry_block; - - public: - llvm::BasicBlock* entry_block() const { - return _entry_block; - } - - public: - void initialize(); - - public: - void add_incoming(SharkState* incoming_state); - - // Method - public: - llvm::Value* method() { - return current_state()->method(); - } - - // Temporary oop storage - public: - void set_oop_tmp(llvm::Value* value) { - assert(value, "value must be non-NULL (will be reset by get_oop_tmp)"); - assert(!current_state()->oop_tmp(), "oop_tmp gets and sets must match"); - current_state()->set_oop_tmp(value); - } - llvm::Value* get_oop_tmp() { - llvm::Value* value = current_state()->oop_tmp(); - assert(value, "oop_tmp gets and sets must match"); - current_state()->set_oop_tmp(NULL); - return value; - } - - // Cache and decache - private: - void decache_for_Java_call(ciMethod* callee); - void cache_after_Java_call(ciMethod* callee); - void decache_for_VM_call(); - void cache_after_VM_call(); - void decache_for_trap(); - - // Monitors - private: - int num_monitors() { - return current_state()->num_monitors(); - } - int set_num_monitors(int num_monitors) { - current_state()->set_num_monitors(num_monitors); - } - - // Code generation - public: - void emit_IR(); - - // Branch helpers - private: - void do_branch(int successor_index); - - // Zero checks - private: - void do_zero_check(SharkValue* value); - void zero_check_value(SharkValue* value, llvm::BasicBlock* continue_block); - - public: - void do_deferred_zero_check(SharkValue* value, - int bci, - SharkState* saved_state, - llvm::BasicBlock* continue_block); - // Exceptions - private: - llvm::Value* pending_exception_address() const { - return builder()->CreateAddressOfStructEntry( - thread(), Thread::pending_exception_offset(), - llvm::PointerType::getUnqual(SharkType::oop_type()), - "pending_exception_addr"); - } - llvm::LoadInst* get_pending_exception() const { - return builder()->CreateLoad( - pending_exception_address(), "pending_exception"); - } - void clear_pending_exception() const { - builder()->CreateStore(LLVMValue::null(), pending_exception_address()); - } - public: - enum ExceptionActionMask { - // The actual bitmasks that things test against - EAM_CHECK = 1, // whether to check for pending exceptions - EAM_HANDLE = 2, // whether to attempt to handle pending exceptions - EAM_MONITOR_FUDGE = 4, // whether the monitor count needs adjusting - - // More convenient values for passing - EX_CHECK_NONE = 0, - EX_CHECK_NO_CATCH = EAM_CHECK, - EX_CHECK_FULL = EAM_CHECK | EAM_HANDLE - }; - void check_pending_exception(int action); - void handle_exception(llvm::Value* exception, int action); - void marshal_exception_fast(int num_options); - void marshal_exception_slow(int num_options); - llvm::BasicBlock* handler_for_exception(int index); - - // VM calls - private: - llvm::CallInst* call_vm(llvm::Value* callee, - llvm::Value** args_start, - llvm::Value** args_end, - int exception_action) { - decache_for_VM_call(); - stack()->CreateSetLastJavaFrame(); - llvm::CallInst *res = builder()->CreateCall(callee, llvm::makeArrayRef(args_start, args_end)); - stack()->CreateResetLastJavaFrame(); - cache_after_VM_call(); - if (exception_action & EAM_CHECK) { - check_pending_exception(exception_action); - current_state()->set_has_safepointed(true); - } - return res; - } - - public: - llvm::CallInst* call_vm(llvm::Value* callee, - int exception_action) { - llvm::Value *args[] = {thread()}; - return call_vm(callee, args, args + 1, exception_action); - } - llvm::CallInst* call_vm(llvm::Value* callee, - llvm::Value* arg1, - int exception_action) { - llvm::Value *args[] = {thread(), arg1}; - return call_vm(callee, args, args + 2, exception_action); - } - llvm::CallInst* call_vm(llvm::Value* callee, - llvm::Value* arg1, - llvm::Value* arg2, - int exception_action) { - llvm::Value *args[] = {thread(), arg1, arg2}; - return call_vm(callee, args, args + 3, exception_action); - } - llvm::CallInst* call_vm(llvm::Value* callee, - llvm::Value* arg1, - llvm::Value* arg2, - llvm::Value* arg3, - int exception_action) { - llvm::Value *args[] = {thread(), arg1, arg2, arg3}; - return call_vm(callee, args, args + 4, exception_action); - } - - // VM call oop return handling - private: - llvm::LoadInst* get_vm_result() const { - llvm::Value *addr = builder()->CreateAddressOfStructEntry( - thread(), JavaThread::vm_result_offset(), - llvm::PointerType::getUnqual(SharkType::oop_type()), - "vm_result_addr"); - llvm::LoadInst *result = builder()->CreateLoad(addr, "vm_result"); - builder()->CreateStore(LLVMValue::null(), addr); - return result; - } - - // Synchronization - private: - void acquire_lock(llvm::Value* lockee, int exception_action); - void release_lock(int exception_action); - - public: - void acquire_method_lock(); - - // Bounds checks - private: - void check_bounds(SharkValue* array, SharkValue* index); - - // Safepoints - private: - void maybe_add_safepoint(); - void maybe_add_backedge_safepoint(); - - // Loop safepoint removal - private: - bool _can_reach_visited; - - bool can_reach(SharkTopLevelBlock* other); - bool can_reach_helper(SharkTopLevelBlock* other); - - // Traps - private: - llvm::BasicBlock* make_trap(int trap_bci, int trap_request); - void do_trap(int trap_request); - - // Returns - private: - void call_register_finalizer(llvm::Value* receiver); - void handle_return(BasicType type, llvm::Value* exception); - - // arraylength - private: - void do_arraylength(); - - // *aload and *astore - private: - void do_aload(BasicType basic_type); - void do_astore(BasicType basic_type); - - // *return and athrow - private: - void do_return(BasicType type); - void do_athrow(); - - // goto* - private: - void do_goto(); - - // jsr* and ret - private: - void do_jsr(); - void do_ret(); - - // if* - private: - void do_if_helper(llvm::ICmpInst::Predicate p, - llvm::Value* b, - llvm::Value* a, - SharkState* if_taken_state, - SharkState* not_taken_state); - void do_if(llvm::ICmpInst::Predicate p, SharkValue* b, SharkValue* a); - - // tableswitch and lookupswitch - private: - void do_switch(); - - // invoke* - private: - ciMethod* improve_virtual_call(ciMethod* caller, - ciInstanceKlass* klass, - ciMethod* dest_method, - ciType* receiver_type); - llvm::Value* get_direct_callee(ciMethod* method); - llvm::Value* get_virtual_callee(SharkValue* receiver, int vtable_index); - llvm::Value* get_interface_callee(SharkValue* receiver, ciMethod* method); - - void do_call(); - - // checkcast and instanceof - private: - bool static_subtype_check(ciKlass* check_klass, ciKlass* object_klass); - void do_full_instance_check(ciKlass* klass); - void do_trapping_instance_check(ciKlass* klass); - - void do_instance_check(); - bool maybe_do_instanceof_if(); - - // new and *newarray - private: - void do_new(); - void do_newarray(); - void do_anewarray(); - void do_multianewarray(); - - // monitorenter and monitorexit - private: - void do_monitorenter(); - void do_monitorexit(); -}; - -#endif // SHARE_VM_SHARK_SHARKTOPLEVELBLOCK_HPP diff --git a/src/hotspot/share/shark/sharkType.hpp b/src/hotspot/share/shark/sharkType.hpp deleted file mode 100644 index 719722bc79f..00000000000 --- a/src/hotspot/share/shark/sharkType.hpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKTYPE_HPP -#define SHARE_VM_SHARK_SHARKTYPE_HPP - -#include "ci/ciType.hpp" -#include "memory/allocation.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/sharkContext.hpp" -#include "utilities/globalDefinitions.hpp" - -class SharkType : public AllStatic { - private: - static SharkContext& context() { - return SharkContext::current(); - } - - // Basic types - public: - static llvm::Type* void_type() { - return context().void_type(); - } - static llvm::IntegerType* bit_type() { - return context().bit_type(); - } - static llvm::IntegerType* jbyte_type() { - return context().jbyte_type(); - } - static llvm::IntegerType* jshort_type() { - return context().jshort_type(); - } - static llvm::IntegerType* jint_type() { - return context().jint_type(); - } - static llvm::IntegerType* jlong_type() { - return context().jlong_type(); - } - static llvm::Type* jfloat_type() { - return context().jfloat_type(); - } - static llvm::Type* jdouble_type() { - return context().jdouble_type(); - } - static llvm::IntegerType* intptr_type() { - return context().intptr_type(); - } - - // Compound types - public: - static llvm::PointerType* itableOffsetEntry_type() { - return context().itableOffsetEntry_type(); - } - static llvm::PointerType* jniEnv_type() { - return context().jniEnv_type(); - } - static llvm::PointerType* jniHandleBlock_type() { - return context().jniHandleBlock_type(); - } - static llvm::PointerType* Metadata_type() { - return context().Metadata_type(); - } - static llvm::PointerType* klass_type() { - return context().klass_type(); - } - static llvm::PointerType* Method_type() { - return context().Method_type(); - } - static llvm::ArrayType* monitor_type() { - return context().monitor_type(); - } - static llvm::PointerType* oop_type() { - return context().oop_type(); - } - static llvm::PointerType* thread_type() { - return context().thread_type(); - } - static llvm::PointerType* zeroStack_type() { - return context().zeroStack_type(); - } - static llvm::FunctionType* entry_point_type() { - return context().entry_point_type(); - } - static llvm::FunctionType* osr_entry_point_type() { - return context().osr_entry_point_type(); - } - - // Mappings - public: - static llvm::Type* to_stackType(BasicType type) { - return context().to_stackType(type); - } - static llvm::Type* to_stackType(ciType* type) { - return to_stackType(type->basic_type()); - } - static llvm::Type* to_arrayType(BasicType type) { - return context().to_arrayType(type); - } - static llvm::Type* to_arrayType(ciType* type) { - return to_arrayType(type->basic_type()); - } -}; - -#endif // SHARE_VM_SHARK_SHARKTYPE_HPP diff --git a/src/hotspot/share/shark/sharkValue.cpp b/src/hotspot/share/shark/sharkValue.cpp deleted file mode 100644 index 0c4ef006a61..00000000000 --- a/src/hotspot/share/shark/sharkValue.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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 "precompiled.hpp" -#include "ci/ciType.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/llvmValue.hpp" -#include "shark/sharkBuilder.hpp" -#include "shark/sharkValue.hpp" - -using namespace llvm; - -// Cloning - -SharkValue* SharkNormalValue::clone() const { - return SharkValue::create_generic(type(), generic_value(), zero_checked()); -} -SharkValue* SharkPHIValue::clone() const { - return SharkValue::create_phi(type(), (PHINode *) generic_value(), this); -} -SharkValue* SharkAddressValue::clone() const { - return SharkValue::address_constant(address_value()); -} - -// Casting - -bool SharkValue::is_phi() const { - return false; -} -bool SharkPHIValue::is_phi() const { - return true; -} -SharkPHIValue* SharkValue::as_phi() { - ShouldNotCallThis(); -} -SharkPHIValue* SharkPHIValue::as_phi() { - return this; -} - -// Comparison - -bool SharkNormalValue::equal_to(SharkValue *other) const { - return (this->type() == other->type() && - this->generic_value() == other->generic_value() && - this->zero_checked() == other->zero_checked()); -} -bool SharkAddressValue::equal_to(SharkValue *other) const { - return (this->address_value() == other->address_value()); -} - -// Type access - -ciType* SharkValue::type() const { - ShouldNotCallThis(); -} -ciType* SharkNormalValue::type() const { - return _type; -} - -BasicType SharkNormalValue::basic_type() const { - return type()->basic_type(); -} -BasicType SharkAddressValue::basic_type() const { - return T_ADDRESS; -} - -int SharkNormalValue::size() const { - return type()->size(); -} -int SharkAddressValue::size() const { - return 1; -} - -bool SharkValue::is_jint() const { - return false; -} -bool SharkValue::is_jlong() const { - return false; -} -bool SharkValue::is_jfloat() const { - return false; -} -bool SharkValue::is_jdouble() const { - return false; -} -bool SharkValue::is_jobject() const { - return false; -} -bool SharkValue::is_jarray() const { - return false; -} -bool SharkValue::is_address() const { - return false; -} - -bool SharkNormalValue::is_jint() const { - return llvm_value()->getType() == SharkType::jint_type(); -} -bool SharkNormalValue::is_jlong() const { - return llvm_value()->getType() == SharkType::jlong_type(); -} -bool SharkNormalValue::is_jfloat() const { - return llvm_value()->getType() == SharkType::jfloat_type(); -} -bool SharkNormalValue::is_jdouble() const { - return llvm_value()->getType() == SharkType::jdouble_type(); -} -bool SharkNormalValue::is_jobject() const { - return llvm_value()->getType() == SharkType::oop_type(); -} -bool SharkNormalValue::is_jarray() const { - return basic_type() == T_ARRAY; -} -bool SharkAddressValue::is_address() const { - return true; -} - -// Typed conversions from SharkValues - -Value* SharkValue::jint_value() const { - ShouldNotCallThis(); -} -Value* SharkValue::jlong_value() const { - ShouldNotCallThis(); -} -Value* SharkValue::jfloat_value() const { - ShouldNotCallThis(); -} -Value* SharkValue::jdouble_value() const { - ShouldNotCallThis(); -} -Value* SharkValue::jobject_value() const { - ShouldNotCallThis(); -} -Value* SharkValue::jarray_value() const { - ShouldNotCallThis(); -} -int SharkValue::address_value() const { - ShouldNotCallThis(); -} - -Value* SharkNormalValue::jint_value() const { - assert(is_jint(), "should be"); - return llvm_value(); -} -Value* SharkNormalValue::jlong_value() const { - assert(is_jlong(), "should be"); - return llvm_value(); -} -Value* SharkNormalValue::jfloat_value() const { - assert(is_jfloat(), "should be"); - return llvm_value(); -} -Value* SharkNormalValue::jdouble_value() const { - assert(is_jdouble(), "should be"); - return llvm_value(); -} -Value* SharkNormalValue::jobject_value() const { - assert(is_jobject(), "should be"); - return llvm_value(); -} -Value* SharkNormalValue::jarray_value() const { - // XXX assert(is_jarray(), "should be"); - // XXX http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=324 - assert(is_jobject(), "should be"); - return llvm_value(); -} -int SharkAddressValue::address_value() const { - return _bci; -} - -// Type-losing conversions -- use with care! - -Value* SharkNormalValue::generic_value() const { - return llvm_value(); -} -Value* SharkAddressValue::generic_value() const { - return LLVMValue::intptr_constant(address_value()); -} - -Value* SharkValue::intptr_value(SharkBuilder* builder) const { - ShouldNotCallThis(); -} -Value* SharkNormalValue::intptr_value(SharkBuilder* builder) const { - return builder->CreatePtrToInt(jobject_value(), SharkType::intptr_type()); -} - -// Phi-style stuff for SharkPHIState::add_incoming - -void SharkValue::addIncoming(SharkValue *value, BasicBlock* block) { - ShouldNotCallThis(); -} -void SharkPHIValue::addIncoming(SharkValue *value, BasicBlock* block) { - assert(!is_clone(), "shouldn't be"); - ((llvm::PHINode *) generic_value())->addIncoming( - value->generic_value(), block); - if (!value->zero_checked()) - _all_incomers_zero_checked = false; -} -void SharkAddressValue::addIncoming(SharkValue *value, BasicBlock* block) { - assert(this->equal_to(value), "should be"); -} - -// Phi-style stuff for SharkState::merge - -SharkValue* SharkNormalValue::merge(SharkBuilder* builder, - SharkValue* other, - BasicBlock* other_block, - BasicBlock* this_block, - const char* name) { - assert(type() == other->type(), "should be"); - assert(zero_checked() == other->zero_checked(), "should be"); - - PHINode *phi = builder->CreatePHI(SharkType::to_stackType(type()), 0, name); - phi->addIncoming(this->generic_value(), this_block); - phi->addIncoming(other->generic_value(), other_block); - return SharkValue::create_generic(type(), phi, zero_checked()); -} -SharkValue* SharkAddressValue::merge(SharkBuilder* builder, - SharkValue* other, - BasicBlock* other_block, - BasicBlock* this_block, - const char* name) { - assert(this->equal_to(other), "should be"); - return this; -} - -// Repeated null and divide-by-zero check removal - -bool SharkValue::zero_checked() const { - ShouldNotCallThis(); -} -void SharkValue::set_zero_checked(bool zero_checked) { - ShouldNotCallThis(); -} - -bool SharkNormalValue::zero_checked() const { - return _zero_checked; -} -void SharkNormalValue::set_zero_checked(bool zero_checked) { - _zero_checked = zero_checked; -} diff --git a/src/hotspot/share/shark/sharkValue.hpp b/src/hotspot/share/shark/sharkValue.hpp deleted file mode 100644 index 2092f247f0b..00000000000 --- a/src/hotspot/share/shark/sharkValue.hpp +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARKVALUE_HPP -#define SHARE_VM_SHARK_SHARKVALUE_HPP - -#include "ci/ciType.hpp" -#include "memory/allocation.hpp" -#include "shark/llvmHeaders.hpp" -#include "shark/llvmValue.hpp" -#include "shark/sharkType.hpp" - -// Items on the stack and in local variables are tracked using -// SharkValue objects. -// -// All SharkValues are one of two core types, SharkNormalValue -// and SharkAddressValue, but no code outside this file should -// ever refer to those directly. The split is because of the -// way JSRs are handled: the typeflow pass expands them into -// multiple copies, so the return addresses pushed by jsr and -// popped by ret only exist at compile time. Having separate -// classes for these allows us to check that our jsr handling -// is correct, via assertions. -// -// There is one more type, SharkPHIValue, which is a subclass -// of SharkNormalValue with a couple of extra methods. Use of -// SharkPHIValue outside of this file is acceptable, so long -// as it is obtained via SharkValue::as_phi(). - -class SharkBuilder; -class SharkPHIValue; - -class SharkValue : public ResourceObj { - protected: - SharkValue() {} - - // Cloning - public: - virtual SharkValue* clone() const = 0; - - // Casting - public: - virtual bool is_phi() const; - virtual SharkPHIValue* as_phi(); - - // Comparison - public: - virtual bool equal_to(SharkValue* other) const = 0; - - // Type access - public: - virtual BasicType basic_type() const = 0; - virtual ciType* type() const; - - virtual bool is_jint() const; - virtual bool is_jlong() const; - virtual bool is_jfloat() const; - virtual bool is_jdouble() const; - virtual bool is_jobject() const; - virtual bool is_jarray() const; - virtual bool is_address() const; - - virtual int size() const = 0; - - bool is_one_word() const { - return size() == 1; - } - bool is_two_word() const { - return size() == 2; - } - - // Typed conversion from SharkValues - public: - virtual llvm::Value* jint_value() const; - virtual llvm::Value* jlong_value() const; - virtual llvm::Value* jfloat_value() const; - virtual llvm::Value* jdouble_value() const; - virtual llvm::Value* jobject_value() const; - virtual llvm::Value* jarray_value() const; - virtual int address_value() const; - - // Typed conversion to SharkValues - public: - static SharkValue* create_jint(llvm::Value* value, bool zero_checked) { - assert(value->getType() == SharkType::jint_type(), "should be"); - return create_generic(ciType::make(T_INT), value, zero_checked); - } - static SharkValue* create_jlong(llvm::Value* value, bool zero_checked) { - assert(value->getType() == SharkType::jlong_type(), "should be"); - return create_generic(ciType::make(T_LONG), value, zero_checked); - } - static SharkValue* create_jfloat(llvm::Value* value) { - assert(value->getType() == SharkType::jfloat_type(), "should be"); - return create_generic(ciType::make(T_FLOAT), value, false); - } - static SharkValue* create_jdouble(llvm::Value* value) { - assert(value->getType() == SharkType::jdouble_type(), "should be"); - return create_generic(ciType::make(T_DOUBLE), value, false); - } - static SharkValue* create_jobject(llvm::Value* value, bool zero_checked) { - assert(value->getType() == SharkType::oop_type(), "should be"); - return create_generic(ciType::make(T_OBJECT), value, zero_checked); - } - - // Typed conversion from constants of various types - public: - static SharkValue* jint_constant(jint value) { - return create_jint(LLVMValue::jint_constant(value), value != 0); - } - static SharkValue* jlong_constant(jlong value) { - return create_jlong(LLVMValue::jlong_constant(value), value != 0); - } - static SharkValue* jfloat_constant(jfloat value) { - return create_jfloat(LLVMValue::jfloat_constant(value)); - } - static SharkValue* jdouble_constant(jdouble value) { - return create_jdouble(LLVMValue::jdouble_constant(value)); - } - static SharkValue* null() { - return create_jobject(LLVMValue::null(), false); - } - static inline SharkValue* address_constant(int bci); - - // Type-losing conversions -- use with care! - public: - virtual llvm::Value* generic_value() const = 0; - virtual llvm::Value* intptr_value(SharkBuilder* builder) const; - - static inline SharkValue* create_generic(ciType* type, - llvm::Value* value, - bool zero_checked); - static inline SharkValue* create_phi(ciType* type, - llvm::PHINode* phi, - const SharkPHIValue* parent = NULL); - - // Phi-style stuff - public: - virtual void addIncoming(SharkValue* value, llvm::BasicBlock* block); - virtual SharkValue* merge(SharkBuilder* builder, - SharkValue* other, - llvm::BasicBlock* other_block, - llvm::BasicBlock* this_block, - const char* name) = 0; - - // Repeated null and divide-by-zero check removal - public: - virtual bool zero_checked() const; - virtual void set_zero_checked(bool zero_checked); -}; - -class SharkNormalValue : public SharkValue { - friend class SharkValue; - - protected: - SharkNormalValue(ciType* type, llvm::Value* value, bool zero_checked) - : _type(type), _llvm_value(value), _zero_checked(zero_checked) {} - - private: - ciType* _type; - llvm::Value* _llvm_value; - bool _zero_checked; - - private: - llvm::Value* llvm_value() const { - return _llvm_value; - } - - // Cloning - public: - SharkValue* clone() const; - - // Comparison - public: - bool equal_to(SharkValue* other) const; - - // Type access - public: - ciType* type() const; - BasicType basic_type() const; - int size() const; - - public: - bool is_jint() const; - bool is_jlong() const; - bool is_jfloat() const; - bool is_jdouble() const; - bool is_jobject() const; - bool is_jarray() const; - - // Typed conversions to LLVM values - public: - llvm::Value* jint_value() const; - llvm::Value* jlong_value() const; - llvm::Value* jfloat_value() const; - llvm::Value* jdouble_value() const; - llvm::Value* jobject_value() const; - llvm::Value* jarray_value() const; - - // Type-losing conversions, use with care - public: - llvm::Value* generic_value() const; - llvm::Value* intptr_value(SharkBuilder* builder) const; - - // Phi-style stuff - public: - SharkValue* merge(SharkBuilder* builder, - SharkValue* other, - llvm::BasicBlock* other_block, - llvm::BasicBlock* this_block, - const char* name); - - // Repeated null and divide-by-zero check removal - public: - bool zero_checked() const; - void set_zero_checked(bool zero_checked); -}; - -class SharkPHIValue : public SharkNormalValue { - friend class SharkValue; - - protected: - SharkPHIValue(ciType* type, llvm::PHINode* phi, const SharkPHIValue *parent) - : SharkNormalValue(type, phi, parent && parent->zero_checked()), - _parent(parent), - _all_incomers_zero_checked(true) {} - - private: - const SharkPHIValue* _parent; - bool _all_incomers_zero_checked; - - private: - const SharkPHIValue* parent() const { - return _parent; - } - bool is_clone() const { - return parent() != NULL; - } - - public: - bool all_incomers_zero_checked() const { - if (is_clone()) - return parent()->all_incomers_zero_checked(); - - return _all_incomers_zero_checked; - } - - // Cloning - public: - SharkValue* clone() const; - - // Casting - public: - bool is_phi() const; - SharkPHIValue* as_phi(); - - // Phi-style stuff - public: - void addIncoming(SharkValue *value, llvm::BasicBlock* block); -}; - -class SharkAddressValue : public SharkValue { - friend class SharkValue; - - protected: - SharkAddressValue(int bci) - : _bci(bci) {} - - private: - int _bci; - - // Cloning - public: - SharkValue* clone() const; - - // Comparison - public: - bool equal_to(SharkValue* other) const; - - // Type access - public: - BasicType basic_type() const; - int size() const; - bool is_address() const; - - // Typed conversion from SharkValues - public: - int address_value() const; - - // Type-losing conversion -- use with care! - public: - llvm::Value* generic_value() const; - - // Phi-style stuff - public: - void addIncoming(SharkValue *value, llvm::BasicBlock* block); - SharkValue* merge(SharkBuilder* builder, - SharkValue* other, - llvm::BasicBlock* other_block, - llvm::BasicBlock* this_block, - const char* name); -}; - -// SharkValue methods that can't be declared above - -inline SharkValue* SharkValue::create_generic(ciType* type, - llvm::Value* value, - bool zero_checked) { - return new SharkNormalValue(type, value, zero_checked); -} - -inline SharkValue* SharkValue::create_phi(ciType* type, - llvm::PHINode* phi, - const SharkPHIValue* parent) { - return new SharkPHIValue(type, phi, parent); -} - -inline SharkValue* SharkValue::address_constant(int bci) { - return new SharkAddressValue(bci); -} - -#endif // SHARE_VM_SHARK_SHARKVALUE_HPP diff --git a/src/hotspot/share/shark/shark_globals.hpp b/src/hotspot/share/shark/shark_globals.hpp deleted file mode 100644 index 3ee0b9a1dce..00000000000 --- a/src/hotspot/share/shark/shark_globals.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010 Red Hat, Inc. - * 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. - * - */ - -#ifndef SHARE_VM_SHARK_SHARK_GLOBALS_HPP -#define SHARE_VM_SHARK_SHARK_GLOBALS_HPP - -#include "runtime/globals.hpp" -#include "utilities/macros.hpp" -#ifdef ZERO -# include "shark_globals_zero.hpp" -#endif - -#define SHARK_FLAGS(develop, develop_pd, product, product_pd, diagnostic, diagnostic_pd, notproduct) \ - \ - product(intx, MaxNodeLimit, 65000, \ - "Maximum number of nodes") \ - \ - /* inlining */ \ - product(intx, SharkMaxInlineSize, 32, \ - "Maximum bytecode size of methods to inline when using Shark") \ - \ - product(bool, EliminateNestedLocks, true, \ - "Eliminate nested locks of the same object when possible") \ - \ - product(ccstr, SharkOptimizationLevel, "Default", \ - "The optimization level passed to LLVM, possible values: None, Less, Default and Agressive") \ - \ - /* compiler debugging */ \ - develop(ccstr, SharkPrintTypeflowOf, NULL, \ - "Print the typeflow of the specified method") \ - \ - diagnostic(ccstr, SharkPrintBitcodeOf, NULL, \ - "Print the LLVM bitcode of the specified method") \ - \ - diagnostic(ccstr, SharkPrintAsmOf, NULL, \ - "Print the asm of the specified method") \ - \ - develop(bool, SharkTraceBytecodes, false, \ - "Trace bytecode compilation") \ - \ - diagnostic(bool, SharkTraceInstalls, false, \ - "Trace method installation") \ - \ - diagnostic(bool, SharkPerformanceWarnings, false, \ - "Warn about things that could be made faster") \ - \ - develop(ccstr, SharkVerifyFunction, NULL, \ - "Runs LLVM verify over LLVM IR") \ - - -SHARK_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_PD_DIAGNOSTIC_FLAG, - DECLARE_NOTPRODUCT_FLAG) - -#endif // SHARE_VM_SHARK_SHARK_GLOBALS_HPP diff --git a/src/hotspot/share/trace/noTraceBackend.hpp b/src/hotspot/share/trace/noTraceBackend.hpp index a0b1f33dd26..fc557907c95 100644 --- a/src/hotspot/share/trace/noTraceBackend.hpp +++ b/src/hotspot/share/trace/noTraceBackend.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, 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 @@ -24,7 +24,7 @@ #ifndef SHARE_VM_TRACE_NOTRACEBACKEND_HPP #define SHARE_VM_TRACE_NOTRACEBACKEND_HPP -#include "prims/jni.h" +#include "jni.h" #include "trace/traceTime.hpp" class NoTraceBackend { diff --git a/src/hotspot/share/trace/trace.dtd b/src/hotspot/share/trace/trace.dtd index 3c40dc9ac60..e1de1928f21 100644 --- a/src/hotspot/share/trace/trace.dtd +++ b/src/hotspot/share/trace/trace.dtd @@ -65,7 +65,8 @@ is_instant CDATA "false" is_constant CDATA "false" is_requestable CDATA "false" - experimental CDATA "false"> + experimental CDATA "false" + cutoff CDATA "false"> + + + + + + + + + + + + + + + diff --git a/src/hotspot/share/utilities/bitMap.cpp b/src/hotspot/share/utilities/bitMap.cpp index 21a3229411b..d461772c002 100644 --- a/src/hotspot/share/utilities/bitMap.cpp +++ b/src/hotspot/share/utilities/bitMap.cpp @@ -81,8 +81,10 @@ BitMap::bm_word_t* BitMap::reallocate(const Allocator& allocator, bm_word_t* old if (new_size_in_words > 0) { map = allocator.allocate(new_size_in_words); - Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) map, - MIN2(old_size_in_words, new_size_in_words)); + if (old_map != NULL) { + Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) map, + MIN2(old_size_in_words, new_size_in_words)); + } if (new_size_in_words > old_size_in_words) { clear_range_of_words(map, old_size_in_words, new_size_in_words); @@ -626,7 +628,7 @@ void BitMap::init_pop_count_table() { table[i] = num_set_bits(i); } - if (!Atomic::replace_if_null(table, &_pop_count_table)) { + if (Atomic::cmpxchg(table, &_pop_count_table, (BitMap::idx_t*)NULL) != NULL) { guarantee(_pop_count_table != NULL, "invariant"); FREE_C_HEAP_ARRAY(idx_t, table); } diff --git a/src/hotspot/share/utilities/decoder.cpp b/src/hotspot/share/utilities/decoder.cpp index 248c4a19656..c1790b3325b 100644 --- a/src/hotspot/share/utilities/decoder.cpp +++ b/src/hotspot/share/utilities/decoder.cpp @@ -28,10 +28,8 @@ #include "utilities/decoder.hpp" #include "utilities/vmError.hpp" -#if defined(_WINDOWS) - #include "decoder_windows.hpp" - #include "windbghelp.hpp" -#elif defined(__APPLE__) +#ifndef _WINDOWS +#if defined(__APPLE__) #include "decoder_machO.hpp" #elif defined(AIX) #include "decoder_aix.hpp" @@ -67,9 +65,7 @@ AbstractDecoder* Decoder::get_error_handler_instance() { AbstractDecoder* Decoder::create_decoder() { AbstractDecoder* decoder; -#if defined(_WINDOWS) - decoder = new (std::nothrow) WindowsDecoder(); -#elif defined (__APPLE__) +#if defined (__APPLE__) decoder = new (std::nothrow)MachODecoder(); #elif defined(AIX) decoder = new (std::nothrow)AIXDecoder(); @@ -136,36 +132,12 @@ bool Decoder::demangle(const char* symbol, char* buf, int buflen) { return decoder->demangle(symbol, buf, buflen); } -bool Decoder::can_decode_C_frame_in_vm() { - assert(_shared_decoder_lock != NULL, "Just check"); - bool error_handling_thread = os::current_thread_id() == VMError::first_error_tid; - MutexLockerEx locker(error_handling_thread ? NULL : _shared_decoder_lock, true); - AbstractDecoder* decoder = error_handling_thread ? - get_error_handler_instance(): get_shared_instance(); - assert(decoder != NULL, "null decoder"); - return decoder->can_decode_C_frame_in_vm(); -} - -/* - * Shutdown shared decoder and replace it with - * _do_nothing_decoder. Do nothing with error handler - * instance, since the JVM is going down. - */ -void Decoder::shutdown() { - assert(_shared_decoder_lock != NULL, "Just check"); - MutexLockerEx locker(_shared_decoder_lock, true); - - if (_shared_decoder != NULL && - _shared_decoder != &_do_nothing_decoder) { - delete _shared_decoder; - } - - _shared_decoder = &_do_nothing_decoder; -} - void Decoder::print_state_on(outputStream* st) { -#ifdef _WINDOWS - WindowsDbgHelp::print_state_on(st); -#endif } +bool Decoder::get_source_info(address pc, char* buf, size_t buflen, int* line) { + return false; +} + +#endif // !_WINDOWS + diff --git a/src/hotspot/share/utilities/decoder.hpp b/src/hotspot/share/utilities/decoder.hpp index 5778c29cbfd..b99047b07d4 100644 --- a/src/hotspot/share/utilities/decoder.hpp +++ b/src/hotspot/share/utilities/decoder.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -58,8 +58,6 @@ public: // demangle a C++ symbol virtual bool demangle(const char* symbol, char* buf, int buflen) = 0; - // if the decoder can decode symbols in vm - virtual bool can_decode_C_frame_in_vm() const = 0; virtual decoder_status status() const { return _decoder_status; @@ -99,9 +97,6 @@ public: return false; } - virtual bool can_decode_C_frame_in_vm() const { - return false; - } }; @@ -113,10 +108,11 @@ public: } static bool decode(address pc, char* buf, int buflen, int* offset, const void* base); static bool demangle(const char* symbol, char* buf, int buflen); - static bool can_decode_C_frame_in_vm(); - // shutdown shared instance - static void shutdown(); + // Attempts to retrieve source file name and line number associated with a pc. + // If buf != NULL, points to a buffer of size buflen which will receive the + // file name. File name will be silently truncated if output buffer is too small. + static bool get_source_info(address pc, char* buf, size_t buflen, int* line); static void print_state_on(outputStream* st); diff --git a/src/hotspot/share/utilities/decoder_elf.hpp b/src/hotspot/share/utilities/decoder_elf.hpp index 3faef1ea0d2..8429744acfd 100644 --- a/src/hotspot/share/utilities/decoder_elf.hpp +++ b/src/hotspot/share/utilities/decoder_elf.hpp @@ -39,8 +39,6 @@ public: } virtual ~ElfDecoder(); - bool can_decode_C_frame_in_vm() const { return true; } - bool demangle(const char* symbol, char *buf, int buflen); bool decode(address addr, char *buf, int buflen, int* offset, const char* filepath, bool demangle); bool decode(address addr, char *buf, int buflen, int* offset, const void *base) { diff --git a/src/hotspot/share/utilities/exceptions.cpp b/src/hotspot/share/utilities/exceptions.cpp index cea61a19f9c..622cde92031 100644 --- a/src/hotspot/share/utilities/exceptions.cpp +++ b/src/hotspot/share/utilities/exceptions.cpp @@ -218,10 +218,10 @@ void Exceptions::_throw_cause(Thread* thread, const char* file, int line, Symbol void Exceptions::throw_stack_overflow_exception(Thread* THREAD, const char* file, int line, const methodHandle& method) { Handle exception; if (!THREAD->has_pending_exception()) { - Klass* k = SystemDictionary::StackOverflowError_klass(); - oop e = InstanceKlass::cast(k)->allocate_instance(CHECK); + InstanceKlass* k = SystemDictionary::StackOverflowError_klass(); + oop e = k->allocate_instance(CHECK); exception = Handle(THREAD, e); // fill_in_stack trace does gc - assert(InstanceKlass::cast(k)->is_initialized(), "need to increase java_thread_min_stack_allowed calculation"); + assert(k->is_initialized(), "need to increase java_thread_min_stack_allowed calculation"); if (StackTraceInThrowable) { java_lang_Throwable::fill_in_stack_trace(exception, method()); } @@ -258,25 +258,26 @@ Handle Exceptions::new_exception(Thread *thread, Symbol* name, Handle h_exception; - // Resolve exception klass - InstanceKlass* klass = InstanceKlass::cast(SystemDictionary::resolve_or_fail(name, h_loader, h_protection_domain, true, thread)); + // Resolve exception klass, and check for pending exception below. + Klass* klass = SystemDictionary::resolve_or_fail(name, h_loader, h_protection_domain, true, thread); if (!thread->has_pending_exception()) { assert(klass != NULL, "klass must exist"); // We are about to create an instance - so make sure that klass is initialized - klass->initialize(thread); + InstanceKlass* ik = InstanceKlass::cast(klass); + ik->initialize(thread); if (!thread->has_pending_exception()) { // Allocate new exception - h_exception = klass->allocate_instance_handle(thread); + h_exception = ik->allocate_instance_handle(thread); if (!thread->has_pending_exception()) { JavaValue result(T_VOID); args->set_receiver(h_exception); // Call constructor - JavaCalls::call_special(&result, klass, - vmSymbols::object_initializer_name(), - signature, - args, - thread); + JavaCalls::call_special(&result, ik, + vmSymbols::object_initializer_name(), + signature, + args, + thread); } } } diff --git a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp index f7a0d028d24..bb5dacfd33a 100644 --- a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_VM_UTILITIES_GLOBALDEFINITIONS_GCC_HPP #define SHARE_VM_UTILITIES_GLOBALDEFINITIONS_GCC_HPP -#include "prims/jni.h" +#include "jni.h" // This file holds compiler-dependent includes, // globally used constants & types, class (forward) diff --git a/src/hotspot/share/utilities/globalDefinitions_sparcWorks.hpp b/src/hotspot/share/utilities/globalDefinitions_sparcWorks.hpp index 4881a4750b4..8a15e17bfd3 100644 --- a/src/hotspot/share/utilities/globalDefinitions_sparcWorks.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_sparcWorks.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_VM_UTILITIES_GLOBALDEFINITIONS_SPARCWORKS_HPP #define SHARE_VM_UTILITIES_GLOBALDEFINITIONS_SPARCWORKS_HPP -#include "prims/jni.h" +#include "jni.h" // This file holds compiler-dependent includes, // globally used constants & types, class (forward) diff --git a/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp b/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp index 83ef8e0910c..8b138ca0cdc 100644 --- a/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_VM_UTILITIES_GLOBALDEFINITIONS_VISCPP_HPP #define SHARE_VM_UTILITIES_GLOBALDEFINITIONS_VISCPP_HPP -#include "prims/jni.h" +#include "jni.h" // This file holds compiler-dependent includes, // globally used constants & types, class (forward) diff --git a/src/hotspot/share/utilities/globalDefinitions_xlc.hpp b/src/hotspot/share/utilities/globalDefinitions_xlc.hpp index 1e97e81e1d4..26ec729c137 100644 --- a/src/hotspot/share/utilities/globalDefinitions_xlc.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_xlc.hpp @@ -26,7 +26,7 @@ #ifndef SHARE_VM_UTILITIES_GLOBALDEFINITIONS_XLC_HPP #define SHARE_VM_UTILITIES_GLOBALDEFINITIONS_XLC_HPP -#include "prims/jni.h" +#include "jni.h" // This file holds compiler-dependent includes, // globally used constants & types, class (forward) diff --git a/src/hotspot/share/utilities/hashtable.cpp b/src/hotspot/share/utilities/hashtable.cpp index 21cc4db1487..625616887b3 100644 --- a/src/hotspot/share/utilities/hashtable.cpp +++ b/src/hotspot/share/utilities/hashtable.cpp @@ -190,7 +190,7 @@ template void BasicHashtable::bulk_free_entries(BucketUnlinkCont BasicHashtableEntry* current = _free_list; while (true) { context->_removed_tail->set_next(current); - BasicHashtableEntry* old = (BasicHashtableEntry*)Atomic::cmpxchg_ptr(context->_removed_head, &_free_list, current); + BasicHashtableEntry* old = Atomic::cmpxchg(context->_removed_head, &_free_list, current); if (old == current) { break; } diff --git a/src/hotspot/share/utilities/hashtable.inline.hpp b/src/hotspot/share/utilities/hashtable.inline.hpp index ccbe60106fb..17ab8d89f4f 100644 --- a/src/hotspot/share/utilities/hashtable.inline.hpp +++ b/src/hotspot/share/utilities/hashtable.inline.hpp @@ -78,7 +78,7 @@ template inline void HashtableBucket::set_entry(BasicHashtableEn // SystemDictionary are read without locks. The new entry must be // complete before other threads can be allowed to see it // via a store to _buckets[index]. - OrderAccess::release_store_ptr(&_entry, l); + OrderAccess::release_store(&_entry, l); } @@ -87,7 +87,7 @@ template inline BasicHashtableEntry* HashtableBucket::get_ent // SystemDictionary are read without locks. The new entry must be // complete before other threads can be allowed to see it // via a store to _buckets[index]. - return (BasicHashtableEntry*) OrderAccess::load_ptr_acquire(&_entry); + return OrderAccess::load_acquire(&_entry); } diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp index ce284a868c6..bf9ba54ef99 100644 --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -346,14 +346,6 @@ #define NOT_ZERO(code) code #endif -#if defined(SHARK) -#define SHARK_ONLY(code) code -#define NOT_SHARK(code) -#else -#define SHARK_ONLY(code) -#define NOT_SHARK(code) code -#endif - #if defined(IA32) || defined(AMD64) #define X86 #define X86_ONLY(code) code diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index e6de87fac79..bea1dbef648 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -189,20 +189,10 @@ void VMError::print_stack_trace(outputStream* st, JavaThread* jt, if (!has_last_Java_frame) jt->set_last_Java_frame(); st->print("Java frames:"); - - // If the top frame is a Shark frame and the frame anchor isn't - // set up then it's possible that the information in the frame - // is garbage: it could be from a previous decache, or it could - // simply have never been written. So we print a warning... - StackFrameStream sfs(jt); - if (!has_last_Java_frame && !sfs.is_done()) { - if (sfs.current()->zeroframe()->is_shark_frame()) { - st->print(" (TOP FRAME MAY BE JUNK)"); - } - } st->cr(); // Print the frames + StackFrameStream sfs(jt); for(int i = 0; !sfs.is_done(); sfs.next(), i++) { sfs.current()->zero_print_on_error(i, st, buf, buflen); st->cr(); @@ -232,6 +222,13 @@ void VMError::print_native_stack(outputStream* st, frame fr, Thread* t, char* bu int count = 0; while (count++ < StackPrintLimit) { fr.print_on_error(st, buf, buf_size); + if (fr.pc()) { // print source file and line, if available + char buf[128]; + int line_no; + if (Decoder::get_source_info(fr.pc(), buf, sizeof(buf), &line_no)) { + st->print(" (%s:%d)", buf, line_no); + } + } st->cr(); // Compiled code may use EBP register on x86 so it looks like // non-walkable C frame. Use frame.sender() for java frames. @@ -1269,7 +1266,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt } intptr_t mytid = os::current_thread_id(); if (first_error_tid == -1 && - Atomic::cmpxchg_ptr(mytid, &first_error_tid, -1) == -1) { + Atomic::cmpxchg(mytid, &first_error_tid, (intptr_t)-1) == -1) { // Initialize time stamps to use the same base. out.time_stamp().update_to(1); diff --git a/src/java.base/share/classes/java/lang/ClassLoader.java b/src/java.base/share/classes/java/lang/ClassLoader.java index e7d33158471..9a60f55ea48 100644 --- a/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/src/java.base/share/classes/java/lang/ClassLoader.java @@ -2381,7 +2381,7 @@ public abstract class ClassLoader { private int jniVersion; // the class from which the library is loaded, also indicates // the loader this native library belongs. - private final Class fromClass; + private Class fromClass; // the canonicalized name of the native library. // or static library name String name; @@ -2404,6 +2404,8 @@ public abstract class ClassLoader { protected void finalize() { synchronized (loadedLibraryNames) { if (fromClass.getClassLoader() != null && loaded) { + this.fromClass = null; // no context when unloaded + /* remove the native library name */ int size = loadedLibraryNames.size(); for (int i = 0; i < size; i++) { diff --git a/src/java.base/share/classes/java/lang/Math.java b/src/java.base/share/classes/java/lang/Math.java index 14093908c6e..dffce353746 100644 --- a/src/java.base/share/classes/java/lang/Math.java +++ b/src/java.base/share/classes/java/lang/Math.java @@ -1094,6 +1094,7 @@ public final class Math { * @return the result * @since 9 */ + @HotSpotIntrinsicCandidate public static long multiplyHigh(long x, long y) { if (x < 0 || y < 0) { // Use technique from section 8-2 of Henry S. Warren, Jr., diff --git a/src/java.base/share/classes/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat b/src/java.base/share/classes/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat deleted file mode 100644 index a634d5b03d4..00000000000 --- a/src/java.base/share/classes/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat +++ /dev/null @@ -1,4 +0,0 @@ -BOOT -@@BOOT_MODULE_NAMES@@ -PLATFORM -@@PLATFORM_MODULE_NAMES@@ diff --git a/src/java.base/share/lib/security/default.policy b/src/java.base/share/lib/security/default.policy index a68dfa1cdeb..c5d6fd9bf9b 100644 --- a/src/java.base/share/lib/security/default.policy +++ b/src/java.base/share/lib/security/default.policy @@ -154,6 +154,10 @@ grant codeBase "jrt:/jdk.internal.vm.compiler" { permission java.security.AllPermission; }; +grant codeBase "jrt:/jdk.internal.vm.compiler.management" { + permission java.security.AllPermission; +}; + grant codeBase "jrt:/jdk.jsobject" { permission java.security.AllPermission; }; diff --git a/src/java.base/share/native/include/jni.h b/src/java.base/share/native/include/jni.h index e29bf04b4cc..e15503f4d4f 100644 --- a/src/java.base/share/native/include/jni.h +++ b/src/java.base/share/native/include/jni.h @@ -1964,6 +1964,7 @@ JNI_OnUnload(JavaVM *vm, void *reserved); #define JNI_VERSION_1_6 0x00010006 #define JNI_VERSION_1_8 0x00010008 #define JNI_VERSION_9 0x00090000 +#define JNI_VERSION_10 0x000a0000 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/java.instrument/share/native/libinstrument/JPLISAgent.c b/src/java.instrument/share/native/libinstrument/JPLISAgent.c index fa1341f414b..01edc8d451d 100644 --- a/src/java.instrument/share/native/libinstrument/JPLISAgent.c +++ b/src/java.instrument/share/native/libinstrument/JPLISAgent.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -783,7 +783,10 @@ getModuleObject(jvmtiEnv* jvmti, int len = (last_slash == NULL) ? 0 : (int)(last_slash - cname); char* pkg_name_buf = (char*)malloc(len + 1); - jplis_assert_msg(pkg_name_buf != NULL, "OOM error in native tmp buffer allocation"); + if (pkg_name_buf == NULL) { + fprintf(stderr, "OOM error in native tmp buffer allocation"); + return NULL; + } if (last_slash != NULL) { strncpy(pkg_name_buf, cname, len); } diff --git a/src/java.management/share/classes/java/lang/management/ThreadMXBean.java b/src/java.management/share/classes/java/lang/management/ThreadMXBean.java index 48fafa5f248..f8b48736821 100644 --- a/src/java.management/share/classes/java/lang/management/ThreadMXBean.java +++ b/src/java.management/share/classes/java/lang/management/ThreadMXBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -687,52 +687,13 @@ public interface ThreadMXBean extends PlatformManagedObject { /** * Returns the thread info for each thread - * whose ID is in the input array {@code ids}, with stack trace - * and synchronization information. - * - *

    - * This method obtains a snapshot of the thread information - * for each thread including: - *

      - *
    • the entire stack trace,
    • - *
    • the object monitors currently locked by the thread - * if {@code lockedMonitors} is {@code true}, and
    • - *
    • the - * ownable synchronizers currently locked by the thread - * if {@code lockedSynchronizers} is {@code true}.
    • - *
    - *

    - * This method returns an array of the {@code ThreadInfo} objects, - * each is the thread information about the thread with the same index - * as in the {@code ids} array. - * If a thread of the given ID is not alive or does not exist, - * {@code null} will be set in the corresponding element - * in the returned array. A thread is alive if - * it has been started and has not yet died. - *

    - * If a thread does not lock any object monitor or {@code lockedMonitors} - * is {@code false}, the returned {@code ThreadInfo} object will have an - * empty {@code MonitorInfo} array. Similarly, if a thread does not - * lock any synchronizer or {@code lockedSynchronizers} is {@code false}, - * the returned {@code ThreadInfo} object - * will have an empty {@code LockInfo} array. - * - *

    - * When both {@code lockedMonitors} and {@code lockedSynchronizers} - * parameters are {@code false}, it is equivalent to calling: - *

    -     *     {@link #getThreadInfo(long[], int)  getThreadInfo(ids, Integer.MAX_VALUE)}
    -     * 
    - * - *

    - * This method is designed for troubleshooting use, but not for - * synchronization control. It might be an expensive operation. - * - *

    - * MBeanServer access:
    - * The mapped type of {@code ThreadInfo} is - * {@code CompositeData} with attributes as specified in the - * {@link ThreadInfo#from ThreadInfo.from} method. + * whose ID is in the input array {@code ids}, + * with stack trace and synchronization information. + * This is equivalent to calling: + *

    + * {@link #getThreadInfo(long[], boolean, boolean, int) + * getThreadInfo(ids, lockedMonitors, lockedSynchronizers, Integer.MAX_VALUE)} + *
    * * @param ids an array of thread IDs. * @param lockedMonitors if {@code true}, retrieves all locked monitors. @@ -763,18 +724,110 @@ public interface ThreadMXBean extends PlatformManagedObject { * * @since 1.6 */ - public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers); + public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, + boolean lockedSynchronizers); + + /** + * Returns the thread info for each thread whose ID + * is in the input array {@code ids}, + * with stack trace of the specified maximum number of elements + * and synchronization information. + * If {@code maxDepth == 0}, no stack trace of the thread + * will be dumped. + * + *

    + * This method obtains a snapshot of the thread information + * for each thread including: + *

      + *
    • stack trace of the specified maximum number of elements,
    • + *
    • the object monitors currently locked by the thread + * if {@code lockedMonitors} is {@code true}, and
    • + *
    • the + * ownable synchronizers currently locked by the thread + * if {@code lockedSynchronizers} is {@code true}.
    • + *
    + *

    + * This method returns an array of the {@code ThreadInfo} objects, + * each is the thread information about the thread with the same index + * as in the {@code ids} array. + * If a thread of the given ID is not alive or does not exist, + * {@code null} will be set in the corresponding element + * in the returned array. A thread is alive if + * it has been started and has not yet died. + *

    + * If a thread does not lock any object monitor or {@code lockedMonitors} + * is {@code false}, the returned {@code ThreadInfo} object will have an + * empty {@code MonitorInfo} array. Similarly, if a thread does not + * lock any synchronizer or {@code lockedSynchronizers} is {@code false}, + * the returned {@code ThreadInfo} object + * will have an empty {@code LockInfo} array. + * + *

    + * When both {@code lockedMonitors} and {@code lockedSynchronizers} + * parameters are {@code false}, it is equivalent to calling: + *

    +     *     {@link #getThreadInfo(long[], int)  getThreadInfo(ids, maxDepth)}
    +     * 
    + * + *

    + * This method is designed for troubleshooting use, but not for + * synchronization control. It might be an expensive operation. + * + *

    + * MBeanServer access:
    + * The mapped type of {@code ThreadInfo} is + * {@code CompositeData} with attributes as specified in the + * {@link ThreadInfo#from ThreadInfo.from} method. + * + * @implSpec The default implementation throws + * {@code UnsupportedOperationException}. + * + * @param ids an array of thread IDs. + * @param lockedMonitors if {@code true}, retrieves all locked monitors. + * @param lockedSynchronizers if {@code true}, retrieves all locked + * ownable synchronizers. + * @param maxDepth indicates the maximum number of + * {@link StackTraceElement} to be retrieved from the stack trace. + * + * @return an array of the {@link ThreadInfo} objects, each containing + * information about a thread whose ID is in the corresponding + * element of the input array of IDs. + * + * @throws IllegalArgumentException if {@code maxDepth} is negative. + * @throws java.lang.SecurityException if a security manager + * exists and the caller does not have + * ManagementPermission("monitor"). + * @throws java.lang.UnsupportedOperationException + *

      + *
    • if {@code lockedMonitors} is {@code true} but + * the Java virtual machine does not support monitoring + * of {@linkplain #isObjectMonitorUsageSupported + * object monitor usage}; or
    • + *
    • if {@code lockedSynchronizers} is {@code true} but + * the Java virtual machine does not support monitoring + * of {@linkplain #isSynchronizerUsageSupported + * ownable synchronizer usage}.
    • + *
    + * + * @see #isObjectMonitorUsageSupported + * @see #isSynchronizerUsageSupported + * + * @since 10 + */ + + public default ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, + boolean lockedSynchronizers, int maxDepth) { + throw new UnsupportedOperationException(); + } /** * Returns the thread info for all live threads with stack trace * and synchronization information. - * Some threads included in the returned array - * may have been terminated when this method returns. - * - *

    - * This method returns an array of {@link ThreadInfo} objects - * as specified in the {@link #getThreadInfo(long[], boolean, boolean)} - * method. + * This is equivalent to calling: + *

    + * {@link #dumpAllThreads(boolean, boolean, int) + * dumpAllThreads(lockedMonitors, lockedSynchronizers, Integer.MAX_VALUE)} + *
    * * @param lockedMonitors if {@code true}, dump all locked monitors. * @param lockedSynchronizers if {@code true}, dump all locked @@ -803,4 +856,56 @@ public interface ThreadMXBean extends PlatformManagedObject { * @since 1.6 */ public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers); + + + /** + * Returns the thread info for all live threads + * with stack trace of the specified maximum number of elements + * and synchronization information. + * if {@code maxDepth == 0}, no stack trace of the thread + * will be dumped. + * Some threads included in the returned array + * may have been terminated when this method returns. + * + *

    + * This method returns an array of {@link ThreadInfo} objects + * as specified in the {@link #getThreadInfo(long[], boolean, boolean, int)} + * method. + * + * @implSpec The default implementation throws + * {@code UnsupportedOperationException}. + * + * @param lockedMonitors if {@code true}, dump all locked monitors. + * @param lockedSynchronizers if {@code true}, dump all locked + * ownable synchronizers. + * @param maxDepth indicates the maximum number of + * {@link StackTraceElement} to be retrieved from the stack trace. + * + * @return an array of {@link ThreadInfo} for all live threads. + * + * @throws IllegalArgumentException if {@code maxDepth} is negative. + * @throws java.lang.SecurityException if a security manager + * exists and the caller does not have + * ManagementPermission("monitor"). + * @throws java.lang.UnsupportedOperationException + *

      + *
    • if {@code lockedMonitors} is {@code true} but + * the Java virtual machine does not support monitoring + * of {@linkplain #isObjectMonitorUsageSupported + * object monitor usage}; or
    • + *
    • if {@code lockedSynchronizers} is {@code true} but + * the Java virtual machine does not support monitoring + * of {@linkplain #isSynchronizerUsageSupported + * ownable synchronizer usage}.
    • + *
    + * + * @see #isObjectMonitorUsageSupported + * @see #isSynchronizerUsageSupported + * + * @since 10 + */ + public default ThreadInfo[] dumpAllThreads(boolean lockedMonitors, + boolean lockedSynchronizers, int maxDepth) { + throw new UnsupportedOperationException(); + } } diff --git a/src/java.management/share/classes/module-info.java b/src/java.management/share/classes/module-info.java index 2b2054cb724..26f34ba21b9 100644 --- a/src/java.management/share/classes/module-info.java +++ b/src/java.management/share/classes/module-info.java @@ -64,7 +64,8 @@ module java.management { exports sun.management.counter.perf to jdk.management.agent; exports sun.management.spi to - jdk.management; + jdk.management, + jdk.internal.vm.compiler.management; uses javax.management.remote.JMXConnectorProvider; uses javax.management.remote.JMXConnectorServerProvider; diff --git a/src/java.management/share/classes/sun/management/ThreadImpl.java b/src/java.management/share/classes/sun/management/ThreadImpl.java index 129ecfcc5da..9e6d8e274bd 100644 --- a/src/java.management/share/classes/sun/management/ThreadImpl.java +++ b/src/java.management/share/classes/sun/management/ThreadImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -463,20 +463,43 @@ public class ThreadImpl implements ThreadMXBean { public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers) { + return dumpThreads0(ids, lockedMonitors, lockedSynchronizers, + Integer.MAX_VALUE); + } + + public ThreadInfo[] getThreadInfo(long[] ids, + boolean lockedMonitors, + boolean lockedSynchronizers, + int maxDepth) { + if (maxDepth < 0) { + throw new IllegalArgumentException( + "Invalid maxDepth parameter: " + maxDepth); + } verifyThreadIds(ids); // ids has been verified to be non-null // an empty array of ids should return an empty array of ThreadInfos if (ids.length == 0) return new ThreadInfo[0]; verifyDumpThreads(lockedMonitors, lockedSynchronizers); - return dumpThreads0(ids, lockedMonitors, lockedSynchronizers); + return dumpThreads0(ids, lockedMonitors, lockedSynchronizers, maxDepth); } @Override public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers) { + return dumpAllThreads(lockedMonitors, lockedSynchronizers, + Integer.MAX_VALUE); + } + + public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, + boolean lockedSynchronizers, + int maxDepth) { + if (maxDepth < 0) { + throw new IllegalArgumentException( + "Invalid maxDepth parameter: " + maxDepth); + } verifyDumpThreads(lockedMonitors, lockedSynchronizers); - return dumpThreads0(null, lockedMonitors, lockedSynchronizers); + return dumpThreads0(null, lockedMonitors, lockedSynchronizers, maxDepth); } // VM support where maxDepth == -1 to request entire stack dump @@ -497,7 +520,8 @@ public class ThreadImpl implements ThreadMXBean { private static native void resetPeakThreadCount0(); private static native ThreadInfo[] dumpThreads0(long[] ids, boolean lockedMonitors, - boolean lockedSynchronizers); + boolean lockedSynchronizers, + int maxDepth); // tid == 0 to reset contention times for all threads private static native void resetContentionTimes0(long tid); diff --git a/src/java.management/share/native/include/jmm.h b/src/java.management/share/native/include/jmm.h index 9e21296bc0b..d4adc367fd9 100644 --- a/src/java.management/share/native/include/jmm.h +++ b/src/java.management/share/native/include/jmm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -50,7 +50,8 @@ enum { JMM_VERSION_1_2 = 0x20010200, // JDK 7 JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA JMM_VERSION_1_2_2 = 0x20010202, - JMM_VERSION = 0x20010203 + JMM_VERSION_2 = 0x20020000, // JDK 10 + JMM_VERSION = 0x20020000 }; typedef struct { @@ -315,7 +316,8 @@ typedef struct jmmInterface_1_ { jobjectArray (JNICALL *DumpThreads) (JNIEnv *env, jlongArray ids, jboolean lockedMonitors, - jboolean lockedSynchronizers); + jboolean lockedSynchronizers, + jint maxDepth); void (JNICALL *SetGCNotificationEnabled) (JNIEnv *env, jobject mgr, jboolean enabled); diff --git a/src/java.management/share/native/libmanagement/ThreadImpl.c b/src/java.management/share/native/libmanagement/ThreadImpl.c index 9e1baadf15c..1dd0b001cfc 100644 --- a/src/java.management/share/native/libmanagement/ThreadImpl.c +++ b/src/java.management/share/native/libmanagement/ThreadImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -135,7 +135,9 @@ Java_sun_management_ThreadImpl_resetContentionTimes0 JNIEXPORT jobjectArray JNICALL Java_sun_management_ThreadImpl_dumpThreads0 - (JNIEnv *env, jclass cls, jlongArray ids, jboolean lockedMonitors, jboolean lockedSynchronizers) + (JNIEnv *env, jclass cls, jlongArray ids, jboolean lockedMonitors, + jboolean lockedSynchronizers, jint maxDepth) { - return jmm_interface->DumpThreads(env, ids, lockedMonitors, lockedSynchronizers); + return jmm_interface->DumpThreads(env, ids, lockedMonitors, + lockedSynchronizers, maxDepth); } diff --git a/src/java.management/share/native/libmanagement/management.c b/src/java.management/share/native/libmanagement/management.c index d909416719e..281e3d0ffac 100644 --- a/src/java.management/share/native/libmanagement/management.c +++ b/src/java.management/share/native/libmanagement/management.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -44,7 +44,7 @@ JNIEXPORT jint JNICALL return JNI_ERR; } - jmm_interface = (JmmInterface*) JVM_GetManagement(JMM_VERSION_1_0); + jmm_interface = (JmmInterface*) JVM_GetManagement(JMM_VERSION); if (jmm_interface == NULL) { JNU_ThrowInternalError(env, "Unsupported Management version"); return JNI_ERR; diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java index a3fc7141b7d..9e3aa91f4cf 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java @@ -144,6 +144,7 @@ public final class BinaryContainer implements SymbolTable { {"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_dynamic_invoke", "_aot_resolve_dynamic_invoke"}, {"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"}, diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java index cb23fefa62a..3c96f630fd9 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java @@ -33,6 +33,7 @@ import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.hotspot.HotSpotBackend; import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin; import org.graalvm.compiler.java.GraphBuilderPhase; import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; import org.graalvm.compiler.lir.phases.LIRSuites; @@ -63,13 +64,13 @@ final class AOTBackend { private final PhaseSuite graphBuilderSuite; private final HighTierContext highTierContext; - AOTBackend(Main main, OptionValues graalOptions, HotSpotBackend backend) { + AOTBackend(Main main, OptionValues graalOptions, HotSpotBackend backend, HotSpotInvokeDynamicPlugin inokeDynamicPlugin) { this.main = main; this.graalOptions = graalOptions; this.backend = backend; providers = backend.getProviders(); codeCache = providers.getCodeCache(); - graphBuilderSuite = initGraphBuilderSuite(backend, main.options.compileWithAssertions); + graphBuilderSuite = initGraphBuilderSuite(backend, main.options.compileWithAssertions, inokeDynamicPlugin); highTierContext = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.ALL); } @@ -146,13 +147,14 @@ final class AOTBackend { return null; } - private static PhaseSuite initGraphBuilderSuite(HotSpotBackend backend, boolean compileWithAssertions) { + private static PhaseSuite initGraphBuilderSuite(HotSpotBackend backend, boolean compileWithAssertions, HotSpotInvokeDynamicPlugin inokeDynamicPlugin) { 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(); + plugins.setInvokeDynamicPlugin(inokeDynamicPlugin); GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withOmitAssertions(!compileWithAssertions); iterator.next(); diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java index c855c2bf375..db633c362a1 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java @@ -25,24 +25,35 @@ package jdk.tools.jaotc; import java.util.ArrayList; import java.util.HashMap; -import java.util.Map; +import java.util.Set; 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.HotSpotResolvedJavaMethod; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.tools.jaotc.AOTDynamicTypeStore.AdapterLocation; +import jdk.tools.jaotc.AOTDynamicTypeStore.AppendixLocation; +import jdk.tools.jaotc.AOTDynamicTypeStore.Location; + /** * 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. */ final class AOTCompiledClass { + private static AOTDynamicTypeStore dynoStore; + + static void setDynamicTypeStore(AOTDynamicTypeStore s) { + dynoStore = s; + } + static class AOTKlassData { private int gotIndex; // Index (offset/8) to the got in the .metaspace.got section private int classId; // Unique ID @@ -50,29 +61,64 @@ final class AOTCompiledClass { private int compiledMethodsOffset; // Offset to dependent methods data. private int dependentMethodsOffset; - private long fingerprint; // Class fingerprint - private final String name; - private boolean isArray; + private final String metadataName; + HotSpotResolvedObjectType type; /** * List of dependent compiled methods which have a reference to this class. */ private ArrayList dependentMethods; - AOTKlassData(BinaryContainer binaryContainer, String name, long fingerprint, int classId) { + AOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type, int classId) { this.dependentMethods = new ArrayList<>(); this.classId = classId; - this.fingerprint = fingerprint; - this.gotIndex = binaryContainer.addTwoSlotKlassSymbol(name); + this.type = type; + this.metadataName = type.isAnonymous() ? "anon<"+ classId + ">": type.getName(); + this.gotIndex = binaryContainer.addTwoSlotKlassSymbol(metadataName); 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) == '['; } - long getFingerprint() { - return fingerprint; + private String[] getMetaspaceNames() { + String name = metadataName; + Set locs = dynoStore.getDynamicClassLocationsForType(type); + if (locs == null) { + return new String[] {name}; + } else { + ArrayList names = new ArrayList(); + names.add(name); + for (Location l : locs) { + HotSpotResolvedObjectType cpType = l.getHolder(); + AOTKlassData data = getAOTKlassData(cpType); + // We collect dynamic types at parse time, but late inlining + // may record types that don't make it into the final graph. + // We can safely ignore those here. + if (data == null) { + // Not a compiled or inlined method + continue; + } + int cpi = l.getCpi(); + String location = "<"+ data.classId + ":" + cpi + ">"; + if (l instanceof AdapterLocation) { + names.add("adapter" + location); + AdapterLocation a = (AdapterLocation)l; + names.add("adapter:" + a.getMethodId() + location); + } else { + assert l instanceof AppendixLocation; + names.add("appendix" + location); + } + } + return names.toArray(new String[names.size()]); + } + } + + HotSpotResolvedObjectType getType() { + return type; + } + + String getMetadataName() { + return metadataName; } /** @@ -112,6 +158,7 @@ final class AOTCompiledClass { for (CompiledMethodInfo methodInfo : dependentMethods) { dependenciesContainer.appendInt(methodInfo.getCodeId()); } + verify(); // @formatter:off @@ -119,7 +166,9 @@ final class AOTCompiledClass { * The offsets layout should match AOTKlassData structure in AOT JVM runtime */ int offset = container.getByteStreamSize(); - container.createSymbol(offset, Kind.OBJECT, Binding.GLOBAL, 0, name); + for (String name : getMetaspaceNames()) { + 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 @@ -129,13 +178,16 @@ final class AOTCompiledClass { // Add the offset to dependent methods data in the .metaspace.offsets section. appendInt(dependentMethodsOffset). // Add fingerprint. - appendLong(fingerprint); + appendLong(type.getFingerprint()); + // @formatter:on } private void verify() { + String name = type.getName(); assert gotIndex > 0 : "incorrect gotIndex: " + gotIndex + " for klass: " + name; - assert isArray || fingerprint != 0 : "incorrect fingerprint: " + fingerprint + " for klass: " + name; + long fingerprint = type.getFingerprint(); + assert type.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; @@ -148,7 +200,7 @@ final class AOTCompiledClass { /** * List of all collected class data. */ - private static Map klassData = new HashMap<>(); + private static HashMap klassData = new HashMap<>(); /** * List of all methods to be compiled. @@ -269,23 +321,25 @@ final class AOTCompiledClass { */ 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; + assert data.getType() == type : "duplicate classes for name " + name; } else { - data = new AOTKlassData(binaryContainer, name, fingerprint, classesCount++); + data = new AOTKlassData(binaryContainer, type, classesCount++); klassData.put(name, data); } return data; } - synchronized static AOTKlassData getAOTKlassData(String name) { + private synchronized static AOTKlassData getAOTKlassData(String name) { return klassData.get(name); } synchronized static AOTKlassData getAOTKlassData(HotSpotResolvedObjectType type) { - return getAOTKlassData(type.getName()); + String name = type.getName(); + AOTKlassData data = getAOTKlassData(name); + assert data == null || data.getType() == type : "duplicate classes for name " + name; + return data; } void addAOTKlassData(BinaryContainer binaryContainer) { @@ -354,21 +408,55 @@ final class AOTCompiledClass { methodInfo.addMethodOffsets(binaryContainer, container); } String name = resolvedJavaType.getName(); - AOTKlassData data = klassData.get(name); + AOTKlassData data = getAOTKlassData(resolvedJavaType); 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); } static void putAOTKlassData(BinaryContainer binaryContainer) { + // record dynamic types + Set dynoTypes = dynoStore.getDynamicTypes(); + if (dynoTypes != null) { + for (HotSpotResolvedObjectType dynoType : dynoTypes) { + addFingerprintKlassData(binaryContainer, dynoType); + } + } + ReadOnlyDataContainer container = binaryContainer.getKlassesOffsetsContainer(); for (AOTKlassData data : klassData.values()) { data.putAOTKlassData(binaryContainer, container); } } + static HotSpotResolvedObjectType getType(Object ref) { + return (ref instanceof HotSpotResolvedObjectType) ? + (HotSpotResolvedObjectType)ref : + ((HotSpotResolvedJavaMethod)ref).getDeclaringClass(); + } + + static String metadataName(HotSpotResolvedObjectType type) { + AOTKlassData data = getAOTKlassData(type); + assert data != null : "no data for " + type; + return getAOTKlassData(type).getMetadataName(); + } + + private static String metadataName(HotSpotResolvedJavaMethod m) { + return metadataName(m.getDeclaringClass()) + "." + m.getName() + m.getSignature().toMethodDescriptor(); + } + + static String metadataName(Object ref) { + if (ref instanceof HotSpotResolvedJavaMethod) { + HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod)ref; + return metadataName(m); + } else { + assert ref instanceof HotSpotResolvedObjectType : "unexpected object type " + ref.getClass().getName(); + HotSpotResolvedObjectType type = (HotSpotResolvedObjectType)ref; + return metadataName(type); + } + } + boolean representsStubs() { return representsStubs; } diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTDynamicTypeStore.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTDynamicTypeStore.java new file mode 100644 index 00000000000..6a8ecdb36ac --- /dev/null +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTDynamicTypeStore.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2017, 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.hotspot.meta.HotSpotInvokeDynamicPlugin.DynamicTypeStore; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; + +import jdk.vm.ci.hotspot.HotSpotConstantPool; +import jdk.vm.ci.hotspot.HotSpotConstantPoolObject; +import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.ConstantPool; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +final class AOTDynamicTypeStore implements DynamicTypeStore { + + public static class Location { + private HotSpotResolvedObjectType holder; + private int cpi; + + Location(HotSpotResolvedObjectType holder, int cpi) { + this.holder = holder; + this.cpi = cpi; + } + + public HotSpotResolvedObjectType getHolder() { + return holder; + } + public int getCpi() { + return cpi; + } + public String toString() { + return getHolder().getName() + "@" + cpi; + } + public int hashCode() { + return holder.hashCode() + getClass().hashCode() + cpi; + } + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (getClass() != o.getClass()) { + return false; + } + Location l = (Location)o; + return cpi == l.cpi && holder.equals(l.holder); + } + } + + public static class AdapterLocation extends Location { + private int methodId; + + AdapterLocation(HotSpotResolvedObjectType holder, int cpi, int methodId) { + super(holder, cpi); + this.methodId = methodId; + } + public int getMethodId() { + return methodId; + } + public String toString() { + return "adapter:" + methodId + "@" + super.toString(); + } + } + + public static class AppendixLocation extends Location { + AppendixLocation(HotSpotResolvedObjectType holder, int cpi) { + super(holder, cpi); + } + public String toString() { + return "appendix@" + super.toString(); + } + } + + private HashMap> typeMap = new HashMap<>(); + private HashMap> holderMap = new HashMap<>(); + + public Set getDynamicTypes() { + synchronized (typeMap) { + return typeMap.keySet(); + } + } + + public Set getDynamicHolders() { + synchronized (holderMap) { + return holderMap.keySet(); + } + } + + @Override + public void recordAdapter(int opcode, HotSpotResolvedObjectType holder, int index, HotSpotResolvedJavaMethod adapter) { + int cpi = ((HotSpotConstantPool)holder.getConstantPool()).rawIndexToConstantPoolIndex(index, opcode); + int methodId = adapter.methodIdnum(); + HotSpotResolvedObjectType adapterType = adapter.getDeclaringClass(); + recordDynamicTypeLocation(new AdapterLocation(holder, cpi, methodId), adapterType); + } + + @Override + public JavaConstant recordAppendix(int opcode, HotSpotResolvedObjectType holder, int index, JavaConstant appendix) { + int cpi = ((HotSpotConstantPool)holder.getConstantPool()).rawIndexToConstantPoolIndex(index, opcode); + HotSpotResolvedObjectType appendixType = ((HotSpotObjectConstant)appendix).getType(); + recordDynamicTypeLocation(new AppendixLocation(holder, cpi), appendixType); + // Make the constant locatable + return HotSpotConstantPoolObject.forObject(holder, cpi, appendix); + } + + private static void recordDynamicMapValue(HashMap> map, HotSpotResolvedObjectType type, T v) { + synchronized (map) { + HashSet set = map.get(type); + if (set == null) { + set = new HashSet<>(); + map.put(type, set); + } + set.add(v); + } + } + + private void recordDynamicTypeLocation(Location l, HotSpotResolvedObjectType type) { + recordDynamicMapValue(typeMap, type, l); + HotSpotResolvedObjectType holder = l.getHolder(); + recordDynamicMapValue(holderMap, holder, type); + } + + public Set getDynamicClassLocationsForType(HotSpotResolvedObjectType type) { + synchronized (typeMap) { + return typeMap.get(type); + } + } + + public Set getDynamicTypesForHolder(HotSpotResolvedObjectType holder) { + synchronized (holderMap) { + return holderMap.get(holder); + } + } + +} diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallInfo.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallInfo.java index d827e682897..76ce46fb985 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallInfo.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallInfo.java @@ -32,9 +32,19 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; final class CallInfo { + static boolean isStaticTarget(Call call) { + return !((HotSpotResolvedJavaMethod)call.target).hasReceiver(); + } + + private static boolean isStaticOpcode(Call call) { + int opcode = getByteCode(call) & 0xFF; + return opcode == Bytecodes.INVOKESTATIC || opcode == Bytecodes.INVOKEDYNAMIC || opcode == Bytecodes.INVOKEVIRTUAL /* invokehandle */; + } + static boolean isStaticCall(Call call) { - if (isJavaCall(call)) { - return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESTATIC); + if (isJavaCall(call) && isStaticTarget(call)) { + assert isStaticOpcode(call); + return true; } return false; } @@ -54,7 +64,7 @@ final class CallInfo { } static boolean isVirtualCall(CompiledMethodInfo methodInfo, Call call) { - return isInvokeVirtual(call) && !methodInfo.hasMark(call, MarkId.INVOKESPECIAL); + return isInvokeVirtual(call) && !methodInfo.hasMark(call, MarkId.INVOKESPECIAL) && !isStaticTarget(call); } static boolean isOptVirtualCall(CompiledMethodInfo methodInfo, Call call) { diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java index 128e91bc0db..1e36db01051 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java @@ -25,7 +25,7 @@ package jdk.tools.jaotc; import java.util.concurrent.atomic.AtomicInteger; import java.util.HashMap; -import java.util.Map; +import java.util.HashSet; import jdk.tools.jaotc.binformat.BinaryContainer; import jdk.tools.jaotc.binformat.ReadOnlyDataContainer; @@ -182,12 +182,12 @@ final class CompiledMethodInfo { /** * List of stubs (PLT trampoline). */ - private Map stubs = new HashMap<>(); + private HashMap stubs = new HashMap<>(); /** * List of referenced classes. */ - private Map dependentKlasses = new HashMap<>(); + private HashSet dependentKlasses = new HashSet<>(); /** * Methods count used to generate unique global method id. @@ -209,7 +209,7 @@ final class CompiledMethodInfo { void addMethodOffsets(BinaryContainer binaryContainer, ReadOnlyDataContainer container) { this.methodOffsets.setNameOffset(binaryContainer.addMetaspaceName(name)); this.methodOffsets.addMethodOffsets(container, name); - for (AOTKlassData data : dependentKlasses.values()) { + for (AOTKlassData data : dependentKlasses) { data.addDependentMethod(this); } } @@ -291,17 +291,15 @@ final class CompiledMethodInfo { 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); - } + dependentKlasses.add(klassData); } - AOTKlassData getDependentKlassData(String klassName) { - return dependentKlasses.get(klassName); + AOTKlassData getDependentKlassData(HotSpotResolvedObjectType type) { + AOTKlassData klassData = AOTCompiledClass.getAOTKlassData(type); + if (dependentKlasses.contains(klassData)) { + return klassData; + } + return null; } boolean hasMark(Site call, MarkId id) { diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java index a65ecd5296d..af24057bb73 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java @@ -32,6 +32,7 @@ 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; import org.graalvm.compiler.code.DataSection; import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; @@ -40,6 +41,7 @@ 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.HotSpotConstantPoolObject; import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; import jdk.vm.ci.hotspot.HotSpotObjectConstant; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; @@ -84,18 +86,24 @@ final class DataPatchProcessor { 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); + targetSymbol = AOTCompiledClass.metadataName(type); + gotName = ((action == HotSpotConstantLoadAction.INITIALIZE) ? "got.init." : "got.") + targetSymbol; } else if (metaspaceConstant.asResolvedJavaMethod() != null && action == HotSpotConstantLoadAction.LOAD_COUNTERS) { targetSymbol = "counters." + JavaMethodInfo.uniqueMethodName(metaspaceConstant.asResolvedJavaMethod()); gotName = "got." + targetSymbol; binaryContainer.addCountersSymbol(targetSymbol); } } else if (constant instanceof HotSpotObjectConstant) { - // String constant. HotSpotObjectConstant oopConstant = (HotSpotObjectConstant) constant; - targetSymbol = "ldc." + oopConstant.toValueString(); + if (oopConstant instanceof HotSpotConstantPoolObject) { + HotSpotConstantPoolObject cpo = (HotSpotConstantPoolObject)oopConstant; + // Even if two locations use the same object, resolve separately + targetSymbol = "ldc." + cpo.getCpType().getName() + cpo.getCpi(); + } else { + // String constant. + targetSymbol = "ldc." + oopConstant.toValueString(); + } Integer offset = binaryContainer.addOopSymbol(targetSymbol); gotName = "got.ldc." + offset; } else if (constant instanceof HotSpotSentinelConstant) { diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java index 70bf0de1e8b..948d3407d58 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java @@ -124,6 +124,7 @@ final class JavaCallSiteRelocationSymbol extends CallSiteRelocationSymbol { private static String getResolveSymbolName(CompiledMethodInfo mi, Call call) { String resolveSymbolName; if (CallInfo.isStaticCall(call)) { + assert mi.hasMark(call, MarkId.INVOKESTATIC); resolveSymbolName = BinaryContainer.getResolveStaticEntrySymbolName(); } else if (CallInfo.isSpecialCall(call)) { resolveSymbolName = BinaryContainer.getResolveOptVirtualEntrySymbolName(); diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java index 932e1ea0381..14276da09d3 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java @@ -46,6 +46,7 @@ import org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory; import org.graalvm.compiler.hotspot.HotSpotGraalOptionValues; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.hotspot.HotSpotHostBackend; +import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin; import org.graalvm.compiler.java.GraphBuilderPhase; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import org.graalvm.compiler.options.OptionValues; @@ -159,7 +160,10 @@ public final class Main { System.gc(); } - AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend); + AOTDynamicTypeStore dynoStore = new AOTDynamicTypeStore(); + AOTCompiledClass.setDynamicTypeStore(dynoStore); + + AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, new HotSpotInvokeDynamicPlugin(dynoStore)); SnippetReflectionProvider snippetReflection = aotBackend.getProviders().getSnippetReflection(); AOTCompiler compiler = new AOTCompiler(this, graalOptions, aotBackend, options.threads); classes = compiler.compileClasses(classes); diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java index 1a68fb3cc34..1a73472c928 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java @@ -33,6 +33,7 @@ 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; @@ -40,6 +41,9 @@ import jdk.vm.ci.code.site.Mark; import jdk.vm.ci.hotspot.HotSpotCompiledCode; import jdk.vm.ci.hotspot.HotSpotMetaData; +import static jdk.tools.jaotc.AOTCompiledClass.getType; +import static jdk.tools.jaotc.AOTCompiledClass.metadataName; + final class MetadataBuilder { private final DataBuilder dataBuilder; @@ -168,7 +172,7 @@ final class MetadataBuilder { } private static int addMetadataEntries(BinaryContainer binaryContainer, HotSpotMetaData metaData, CompiledMethodInfo methodInfo) { - String[] metaDataEntries = metaData.metadataEntries(); + Object[] metaDataEntries = metaData.metadataEntries(); if (metaDataEntries.length == 0) { return 0; @@ -177,20 +181,13 @@ final class MetadataBuilder { int metadataGotSlotsStart = binaryContainer.getMetadataGotContainer().getByteStreamSize(); // binaryContainer.reserveMetadataGOTSlots(metaDataEntries.length); for (int index = 0; index < metaDataEntries.length; index++) { - String name = metaDataEntries[index]; - addMetadataEntry(binaryContainer, name); + Object ref = metaDataEntries[index]; + String name = metadataName(ref); // 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); - } + addMetadataEntry(binaryContainer, name); // We should already have added entries for this klass - assert AOTCompiledClass.getAOTKlassData(klassName) != null; - assert methodInfo.getDependentKlassData(klassName) != null; + assert AOTCompiledClass.getAOTKlassData(getType(ref)) != null; + assert methodInfo.getDependentKlassData(getType(ref)) != null; } return metadataGotSlotsStart; diff --git a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java index 4a5fbdd1294..5b021b58c88 100644 --- a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, 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 @@ -32,6 +32,10 @@ import com.sun.tools.attach.spi.AttachProvider; import java.io.InputStream; import java.io.IOException; import java.io.File; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.Files; /* * Linux implementation of HotSpotVirtualMachine @@ -63,12 +67,15 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { throw new AttachNotSupportedException("Invalid process identifier"); } + // Try to resolve to the "inner most" pid namespace + int ns_pid = getNamespacePid(pid); + // Find the socket file. If not found then we attempt to start the // attach mechanism in the target VM by sending it a QUIT signal. // Then we attempt to find the socket file again. - path = findSocketFile(pid); + path = findSocketFile(pid, ns_pid); if (path == null) { - File f = createAttachFile(pid); + File f = createAttachFile(pid, ns_pid); try { sendQuitTo(pid); @@ -83,7 +90,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { try { Thread.sleep(delay); } catch (InterruptedException x) { } - path = findSocketFile(pid); + path = findSocketFile(pid, ns_pid); time_spend += delay; if (time_spend > timeout/2 && path == null) { @@ -262,8 +269,12 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { } // Return the socket file for the given process. - private String findSocketFile(int pid) { - File f = new File(tmpdir, ".java_pid" + pid); + private String findSocketFile(int pid, int ns_pid) { + // A process may not exist in the same mount namespace as the caller. + // Instead, attach relative to the target root filesystem as exposed by + // procfs regardless of namespaces. + String root = "/proc/" + pid + "/root/" + tmpdir; + File f = new File(root, ".java_pid" + ns_pid); if (!f.exists()) { return null; } @@ -274,14 +285,23 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { // if not already started. The client creates a .attach_pid file in the // target VM's working directory (or temp directory), and the SIGQUIT handler // checks for the file. - private File createAttachFile(int pid) throws IOException { - String fn = ".attach_pid" + pid; + private File createAttachFile(int pid, int ns_pid) throws IOException { + String fn = ".attach_pid" + ns_pid; String path = "/proc/" + pid + "/cwd/" + fn; File f = new File(path); try { f.createNewFile(); } catch (IOException x) { - f = new File(tmpdir, fn); + String root; + if (pid != ns_pid) { + // A process may not exist in the same mount namespace as the caller. + // Instead, attach relative to the target root filesystem as exposed by + // procfs regardless of namespaces. + root = "/proc/" + pid + "/root/" + tmpdir; + } else { + root = tmpdir; + } + f = new File(root, fn); f.createNewFile(); } return f; @@ -307,6 +327,40 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { } + // Return the inner most namespaced PID if there is one, + // otherwise return the original PID. + private int getNamespacePid(int pid) throws AttachNotSupportedException, IOException { + // Assuming a real procfs sits beneath, reading this doesn't block + // nor will it consume a lot of memory. + String statusFile = "/proc/" + pid + "/status"; + File f = new File(statusFile); + if (!f.exists()) { + return pid; // Likely a bad pid, but this is properly handled later. + } + + Path statusPath = Paths.get(statusFile); + + try { + for (String line : Files.readAllLines(statusPath, StandardCharsets.UTF_8)) { + String[] parts = line.split(":"); + if (parts.length == 2 && parts[0].trim().equals("NSpid")) { + parts = parts[1].trim().split("\\s+"); + // The last entry represents the PID the JVM "thinks" it is. + // Even in non-namespaced pids these entries should be + // valid. You could refer to it as the inner most pid. + int ns_pid = Integer.parseInt(parts[parts.length - 1]); + return ns_pid; + } + } + // Old kernels may not have NSpid field (i.e. 3.10). + // Fallback to original pid in the event we cannot deduce. + return pid; + } catch (NumberFormatException | IOException x) { + throw new AttachNotSupportedException("Unable to parse namespace"); + } + } + + //-- native methods static native void sendQuitToChildrenOf(int pid) throws IOException; diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/MacosxDebuggerLocal.m b/src/jdk.hotspot.agent/macosx/native/libsaproc/MacosxDebuggerLocal.m index 189353eef2d..c05a29d3e76 100644 --- a/src/jdk.hotspot.agent/macosx/native/libsaproc/MacosxDebuggerLocal.m +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/MacosxDebuggerLocal.m @@ -689,8 +689,15 @@ static bool ptrace_waitpid(pid_t pid) { // attach to a process/thread specified by "pid" static bool ptrace_attach(pid_t pid) { int res; - if ((res = ptrace(PT_ATTACHEXC, pid, 0, 0)) < 0) { - print_error("ptrace(PT_ATTACHEXC, %d) failed with %d\n", pid, res); +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + if ((res = ptrace(PT_ATTACH, pid, 0, 0)) < 0) { + print_error("ptrace(PT_ATTACH, %d) failed with %d\n", pid, res); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif return false; } else { return ptrace_waitpid(pid); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java index 4a7094463d7..6d5720b63a6 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -35,6 +35,7 @@ import sun.jvm.hotspot.compiler.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.gc.parallel.*; import sun.jvm.hotspot.gc.shared.*; +import sun.jvm.hotspot.gc.g1.*; import sun.jvm.hotspot.interpreter.*; import sun.jvm.hotspot.memory.*; import sun.jvm.hotspot.oops.*; @@ -1078,6 +1079,26 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener { } } + } else if (collHeap instanceof G1CollectedHeap) { + G1CollectedHeap heap = (G1CollectedHeap)collHeap; + HeapRegion region = heap.hrm().getByAddress(handle); + + if (region.isFree()) { + anno = "Free "; + bad = false; + } else if (region.isYoung()) { + anno = "Young "; + bad = false; + } else if (region.isHumongous()) { + anno = "Humongous "; + bad = false; + } else if (region.isPinned()) { + anno = "Pinned "; + bad = false; + } else if (region.isOld()) { + anno = "Old "; + bad = false; + } } else if (collHeap instanceof ParallelScavengeHeap) { ParallelScavengeHeap heap = (ParallelScavengeHeap) collHeap; if (heap.youngGen().isIn(handle)) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java index 84ec0a195ea..880b86b6e3e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -71,7 +71,7 @@ public class NMethod extends CompiledMethod { stack. An not_entrant method can be removed when there is no more activations, i.e., when the _stack_traversal_mark is less than current sweep traversal index. */ - private static JLongField stackTraversalMarkField; + private static CIntegerField stackTraversalMarkField; private static CIntegerField compLevelField; @@ -105,7 +105,7 @@ public class NMethod extends CompiledMethod { verifiedEntryPointField = type.getAddressField("_verified_entry_point"); osrEntryPointField = type.getAddressField("_osr_entry_point"); lockCountField = type.getJIntField("_lock_count"); - stackTraversalMarkField = type.getJLongField("_stack_traversal_mark"); + stackTraversalMarkField = type.getCIntegerField("_stack_traversal_mark"); compLevelField = type.getCIntegerField("_comp_level"); pcDescSize = db.lookupType("PcDesc").getSize(); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VMRegImpl.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VMRegImpl.java index 8159437621a..19ae300108e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VMRegImpl.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VMRegImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2017, 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 @@ -37,6 +37,7 @@ public class VMRegImpl { private static int stack0Val; private static Address stack0Addr; private static AddressField regNameField; + private static int stackSlotSize; static { VM.registerVMInitializedObserver(new Observer() { @@ -53,6 +54,7 @@ public class VMRegImpl { stack0Val = (int) stack0Addr.hashCode(); stack0 = new VMReg(stack0Val); regNameField = type.getAddressField("regName[0]"); + stackSlotSize = db.lookupIntConstant("VMRegImpl::stack_slot_size"); } public static VMReg getStack0() { @@ -67,4 +69,8 @@ public class VMRegImpl { long addrSize = VM.getVM().getAddressSize(); return CStringUtilities.getString(regName.getAddressAt(index * addrSize)); } + + public static int getStackSlotSize() { + return stackSlotSize; + } } diff --git a/src/hotspot/share/shark/sharkInvariants.cpp b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/CMSHeap.java similarity index 68% rename from src/hotspot/share/shark/sharkInvariants.cpp rename to src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/CMSHeap.java index 554274a3b89..228cf5b149b 100644 --- a/src/hotspot/share/shark/sharkInvariants.cpp +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/CMSHeap.java @@ -1,6 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. + * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. * 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,15 +22,19 @@ * */ -#include "precompiled.hpp" -#include "shark/sharkInvariants.hpp" +package sun.jvm.hotspot.gc.cms; -int SharkTargetInvariants::count_monitors() { - int result = 0; - if (is_synchronized() || target()->has_monitor_bytecodes()) { - for (int i = 0; i < flow()->block_count(); i++) { - result = MAX2(result, flow()->pre_order_at(i)->monitor_count()); - } +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.gc.shared.GenCollectedHeap; +import sun.jvm.hotspot.gc.shared.CollectedHeapName; + +public class CMSHeap extends GenCollectedHeap { + + public CMSHeap(Address addr) { + super(addr); + } + + public CollectedHeapName kind() { + return CollectedHeapName.CMS_HEAP; } - return result; } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java index a9e91802bba..24ebfe905d3 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -87,7 +87,7 @@ public class G1CollectedHeap extends CollectedHeap { return hrm().length(); } - private HeapRegionManager hrm() { + public HeapRegionManager hrm() { Address hrmAddr = addr.addOffsetTo(hrmFieldOffset); return (HeapRegionManager) VMObjectFactory.newObject(HeapRegionManager.class, hrmAddr); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionTable.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionTable.java index da8abd80223..596db0d53a4 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionTable.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, 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 @@ -29,6 +29,7 @@ import java.util.Observable; import java.util.Observer; import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.debugger.OopHandle; import sun.jvm.hotspot.runtime.VM; import sun.jvm.hotspot.runtime.VMObject; import sun.jvm.hotspot.runtime.VMObjectFactory; @@ -132,4 +133,12 @@ public class G1HeapRegionTable extends VMObject { public G1HeapRegionTable(Address addr) { super(addr); } + + public HeapRegion getByAddress(Address addr) { + long biasedIndex = addr.asLongValue() >>> shiftBy(); + long offset = biasedIndex * HeapRegion.getPointerSize(); + Address result = (addr instanceof OopHandle) ? addr.addOffsetToAsOopHandle(offset) + : addr.addOffsetTo(offset); + return new HeapRegion(result); + } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java index 61b2bb1aec5..e771bb38de1 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -29,9 +29,11 @@ import java.util.List; import java.util.Observable; import java.util.Observer; import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.debugger.OopHandle; import sun.jvm.hotspot.gc.shared.CompactibleSpace; import sun.jvm.hotspot.memory.MemRegion; import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.runtime.VMObjectFactory; import sun.jvm.hotspot.types.AddressField; import sun.jvm.hotspot.types.CIntegerField; import sun.jvm.hotspot.types.Type; @@ -44,6 +46,10 @@ public class HeapRegion extends CompactibleSpace { // static int GrainBytes; static private CIntegerField grainBytesField; static private AddressField topField; + private static long typeFieldOffset; + private static long pointerSize; + + private HeapRegionType type; static { VM.registerVMInitializedObserver(new Observer() { @@ -58,7 +64,9 @@ public class HeapRegion extends CompactibleSpace { grainBytesField = type.getCIntegerField("GrainBytes"); topField = type.getAddressField("_top"); + typeFieldOffset = type.getField("_type").getOffset(); + pointerSize = db.lookupType("HeapRegion*").getSize(); } static public long grainBytes() { @@ -67,6 +75,9 @@ public class HeapRegion extends CompactibleSpace { public HeapRegion(Address addr) { super(addr); + Address typeAddr = (addr instanceof OopHandle) ? addr.addOffsetToAsOopHandle(typeFieldOffset) + : addr.addOffsetTo(typeFieldOffset); + type = (HeapRegionType)VMObjectFactory.newObject(HeapRegionType.class, typeAddr); } public Address top() { @@ -89,4 +100,28 @@ public class HeapRegion extends CompactibleSpace { public long free() { return end().minus(top()); } + + public boolean isFree() { + return type.isFree(); + } + + public boolean isYoung() { + return type.isYoung(); + } + + public boolean isHumongous() { + return type.isHumongous(); + } + + public boolean isPinned() { + return type.isPinned(); + } + + public boolean isOld() { + return type.isOld(); + } + + public static long getPointerSize() { + return pointerSize; + } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java index b80c60350f4..79f32d857b9 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -85,4 +85,8 @@ public class HeapRegionManager extends VMObject { public HeapRegionManager(Address addr) { super(addr); } + + public HeapRegion getByAddress(Address addr) { + return regions().getByAddress(addr); + } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionType.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionType.java new file mode 100644 index 00000000000..cdc706d23bc --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionType.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2017, 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 sun.jvm.hotspot.gc.g1; + +import java.util.Observable; +import java.util.Observer; +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.runtime.VMObject; +import sun.jvm.hotspot.types.CIntegerField; +import sun.jvm.hotspot.types.Type; +import sun.jvm.hotspot.types.TypeDataBase; + +// Mirror class for HeapRegionType. Currently we don't actually include +// any of its fields but only iterate over it. + +public class HeapRegionType extends VMObject { + + private static int freeTag; + private static int youngMask; + private static int humongousMask; + private static int pinnedMask; + private static int oldMask; + private static CIntegerField tagField; + private int tag; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + Type type = db.lookupType("HeapRegionType"); + + tagField = type.getCIntegerField("_tag"); + + freeTag = db.lookupIntConstant("HeapRegionType::FreeTag"); + youngMask = db.lookupIntConstant("HeapRegionType::YoungMask"); + humongousMask = db.lookupIntConstant("HeapRegionType::HumongousMask"); + pinnedMask = db.lookupIntConstant("HeapRegionType::PinnedMask"); + oldMask = db.lookupIntConstant("HeapRegionType::OldMask"); + } + + public boolean isFree() { + return tagField.getValue(addr) == freeTag; + } + + public boolean isYoung() { + return (tagField.getValue(addr) & youngMask) != 0; + } + + public boolean isHumongous() { + return (tagField.getValue(addr) & humongousMask) != 0; + } + + public boolean isPinned() { + return (tagField.getValue(addr) & pinnedMask) != 0; + } + + public boolean isOld() { + return (tagField.getValue(addr) & oldMask) != 0; + } + + public HeapRegionType(Address addr) { + super(addr); + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CollectedHeapName.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CollectedHeapName.java index 13419091e18..57ef89f1fd0 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CollectedHeapName.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CollectedHeapName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -32,6 +32,7 @@ public class CollectedHeapName { private CollectedHeapName(String name) { this.name = name; } public static final CollectedHeapName GEN_COLLECTED_HEAP = new CollectedHeapName("GenCollectedHeap"); + public static final CollectedHeapName CMS_HEAP = new CollectedHeapName("CMSHeap"); public static final CollectedHeapName G1_COLLECTED_HEAP = new CollectedHeapName("G1CollectedHeap"); public static final CollectedHeapName PARALLEL_SCAVENGE_HEAP = new CollectedHeapName("ParallelScavengeHeap"); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java index 23fc9f6ce24..53f7a0b9353 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java @@ -27,6 +27,7 @@ package sun.jvm.hotspot.memory; import java.io.*; import java.util.*; import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.gc.cms.CMSHeap; import sun.jvm.hotspot.gc.shared.*; import sun.jvm.hotspot.gc.g1.G1CollectedHeap; import sun.jvm.hotspot.gc.parallel.*; @@ -77,6 +78,7 @@ public class Universe { heapConstructor = new VirtualConstructor(db); heapConstructor.addMapping("GenCollectedHeap", GenCollectedHeap.class); + heapConstructor.addMapping("CMSHeap", CMSHeap.class); heapConstructor.addMapping("ParallelScavengeHeap", ParallelScavengeHeap.class); heapConstructor.addMapping("G1CollectedHeap", G1CollectedHeap.class); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java index c7285ed316d..b81b01b3881 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java @@ -269,13 +269,12 @@ public class ConstantPool extends Metadata implements ClassConstants { public static int decodeInvokedynamicIndex(int i) { Assert.that(isInvokedynamicIndex(i), ""); return ~i; } - // The invokedynamic points at the object index. The object map points at - // the cpCache index and the cpCache entry points at the original constant - // pool index. + // The invokedynamic points at a CP cache entry. This entry points back + // at the original CP entry (CONSTANT_InvokeDynamic) and also (via f2) at an entry + // in the resolved_references array (which provides the appendix argument). public int invokedynamicCPCacheIndex(int index) { Assert.that(isInvokedynamicIndex(index), "should be a invokedynamic index"); - int rawIndex = decodeInvokedynamicIndex(index); - return referenceMap().at(rawIndex); + return decodeInvokedynamicIndex(index); } ConstantPoolCacheEntry invokedynamicCPCacheEntryAt(int index) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java index bc9431ca126..e2aa52ffd9c 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java @@ -51,7 +51,7 @@ public class Klass extends Metadata implements ClassConstants { private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("Klass"); - javaMirror = new OopField(type.getOopField("_java_mirror"), 0); + javaMirror = type.getAddressField("_java_mirror"); superField = new MetadataField(type.getAddressField("_super"), 0); layoutHelper = new IntField(type.getJIntField("_layout_helper"), 0); name = type.getAddressField("_name"); @@ -88,7 +88,7 @@ public class Klass extends Metadata implements ClassConstants { public boolean isKlass() { return true; } // Fields - private static OopField javaMirror; + private static AddressField javaMirror; private static MetadataField superField; private static IntField layoutHelper; private static AddressField name; @@ -109,7 +109,15 @@ public class Klass extends Metadata implements ClassConstants { } // Accessors for declared fields - public Instance getJavaMirror() { return (Instance) javaMirror.getValue(this); } + public Instance getJavaMirror() { + Address handle = javaMirror.getValue(getAddress()); + if (handle != null) { + // Load through the handle + OopHandle refs = handle.getOopHandleAt(0); + return (Instance)VM.getVM().getObjectHeap().newOop(refs); + } + return null; + } public Klass getSuper() { return (Klass) superField.getValue(this); } public Klass getJavaSuper() { return null; } public int getLayoutHelper() { return (int) layoutHelper.getValue(this); } @@ -185,7 +193,7 @@ public class Klass extends Metadata implements ClassConstants { } public void iterateFields(MetadataVisitor visitor) { - visitor.doOop(javaMirror, true); + // visitor.doOop(javaMirror, true); visitor.doMetadata(superField, true); visitor.doInt(layoutHelper, true); // visitor.doOop(name, true); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicType.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicType.java index 825541c0ea3..8331b5d34ca 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicType.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -28,20 +28,23 @@ package sun.jvm.hotspot.runtime; VM. */ public class BasicType { - public static final int tBoolean = 4; - public static final int tChar = 5; - public static final int tFloat = 6; - public static final int tDouble = 7; - public static final int tByte = 8; - public static final int tShort = 9; - public static final int tInt = 10; - public static final int tLong = 11; - public static final int tObject = 12; - public static final int tArray = 13; - public static final int tVoid = 14; - public static final int tAddress = 15; - public static final int tConflict = 16; - public static final int tIllegal = 99; + public static final int tBoolean = 4; + public static final int tChar = 5; + public static final int tFloat = 6; + public static final int tDouble = 7; + public static final int tByte = 8; + public static final int tShort = 9; + public static final int tInt = 10; + public static final int tLong = 11; + public static final int tObject = 12; + public static final int tArray = 13; + public static final int tVoid = 14; + public static final int tAddress = 15; + public static final int tNarrowOop = 16; + public static final int tMetadata = 17; + public static final int tNarrowKlass = 18; + public static final int tConflict = 19; + public static final int tIllegal = 99; public static final BasicType T_BOOLEAN = new BasicType(tBoolean); public static final BasicType T_CHAR = new BasicType(tChar); @@ -55,6 +58,9 @@ public class BasicType { public static final BasicType T_ARRAY = new BasicType(tArray); public static final BasicType T_VOID = new BasicType(tVoid); public static final BasicType T_ADDRESS = new BasicType(tAddress); + public static final BasicType T_NARROWOOP = new BasicType(tNarrowOop); + public static final BasicType T_METADATA = new BasicType(tMetadata); + public static final BasicType T_NARROWKLASS = new BasicType(tNarrowKlass); public static final BasicType T_CONFLICT = new BasicType(tConflict); public static final BasicType T_ILLEGAL = new BasicType(tIllegal); @@ -106,6 +112,18 @@ public class BasicType { return tAddress; } + public static int getTNarrowOop() { + return tNarrowOop; + } + + public static int getTMetadata() { + return tMetadata; + } + + public static int getTNarrowKlass() { + return tNarrowKlass; + } + /** For stack value type with conflicting contents */ public static int getTConflict() { return tConflict; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java index ab536d20f5d..d9de87767fd 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -430,7 +430,7 @@ public abstract class Frame implements Cloneable { // If it is passed in a register, it got spilled in the stub frame. return regMap.getLocation(reg); } else { - long spOffset = VM.getVM().getAddressSize() * reg.minus(stack0); + long spOffset = reg.reg2Stack() * VM.getVM().getVMRegImplInfo().getStackSlotSize(); return getUnextendedSP().addOffsetTo(spOffset); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StackValueCollection.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StackValueCollection.java index 2da587843ac..39b12e2489a 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StackValueCollection.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StackValueCollection.java @@ -27,6 +27,7 @@ package sun.jvm.hotspot.runtime; import java.util.*; import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.types.*; public class StackValueCollection { private List list; @@ -48,7 +49,15 @@ public class StackValueCollection { public int intAt(int slot) { return (int) get(slot).getInteger(); } public long longAt(int slot) { return VM.getVM().buildLongFromIntsPD((int) get(slot).getInteger(), (int) get(slot+1).getInteger()); } - public OopHandle oopHandleAt(int slot) { return get(slot).getObject(); } + + public OopHandle oopHandleAt(int slot) { + StackValue sv = get(slot); + if (sv.getType() == BasicType.getTConflict()) { + throw new WrongTypeException("Conflict type"); + } + return sv.getObject(); + } + public float floatAt(int slot) { return Float.intBitsToFloat(intAt(slot)); } public double doubleAt(int slot) { return Double.longBitsToDouble(longAt(slot)); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMReg.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMReg.java index 15c049f8425..f3bdca35f23 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMReg.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMReg.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -84,4 +84,8 @@ public class VMReg { public boolean greaterThanOrEqual(VMReg arg) { return value >= arg.value; } public int minus(VMReg arg) { return value - arg.value; } + + public int reg2Stack() { + return value - VM.getVM().getVMRegImplInfo().getStack0().getValue(); + } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java index 17d24d4f145..d2d639214af 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java @@ -34,6 +34,7 @@ import sun.jvm.hotspot.interpreter.*; import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.tools.jcore.*; +import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.utilities.*; public class HTMLGenerator implements /* imports */ ClassConstants { @@ -1928,11 +1929,16 @@ public class HTMLGenerator implements /* imports */ ClassConstants { } if (!method.isStatic() && !method.isNative()) { - OopHandle oopHandle = vf.getLocals().oopHandleAt(0); + try { + OopHandle oopHandle = vf.getLocals().oopHandleAt(0); - if (oopHandle != null) { - buf.append(", oop = "); - buf.append(oopHandle.toString()); + if (oopHandle != null) { + buf.append(", oop = "); + buf.append(oopHandle.toString()); + } + } catch (WrongTypeException e) { + // Do nothing. + // It might be caused by JIT'ed inline frame. } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java index 7006517548f..8331dc15903 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java @@ -79,9 +79,15 @@ public class SPARCHotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFacto if ((config.vmVersionFeatures & 1L << config.sparc_DES) != 0) { features.add(CPUFeature.DES); } + if ((config.vmVersionFeatures & 1L << config.sparc_DICTUNP) != 0) { + features.add(CPUFeature.DICTUNP); + } if ((config.vmVersionFeatures & 1L << config.sparc_FMAF) != 0) { features.add(CPUFeature.FMAF); } + if ((config.vmVersionFeatures & 1L << config.sparc_FPCMPSHL) != 0) { + features.add(CPUFeature.FPCMPSHL); + } if ((config.vmVersionFeatures & 1L << config.sparc_HPC) != 0) { features.add(CPUFeature.HPC); } @@ -94,6 +100,9 @@ public class SPARCHotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFacto if ((config.vmVersionFeatures & 1L << config.sparc_MD5) != 0) { features.add(CPUFeature.MD5); } + if ((config.vmVersionFeatures & 1L << config.sparc_MME) != 0) { + features.add(CPUFeature.MME); + } if ((config.vmVersionFeatures & 1L << config.sparc_MONT) != 0) { features.add(CPUFeature.MONT); } @@ -112,18 +121,30 @@ public class SPARCHotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFacto if ((config.vmVersionFeatures & 1L << config.sparc_POPC) != 0) { features.add(CPUFeature.POPC); } + if ((config.vmVersionFeatures & 1L << config.sparc_RLE) != 0) { + features.add(CPUFeature.RLE); + } if ((config.vmVersionFeatures & 1L << config.sparc_SHA1) != 0) { features.add(CPUFeature.SHA1); } if ((config.vmVersionFeatures & 1L << config.sparc_SHA256) != 0) { features.add(CPUFeature.SHA256); } + if ((config.vmVersionFeatures & 1L << config.sparc_SHA3) != 0) { + features.add(CPUFeature.SHA3); + } if ((config.vmVersionFeatures & 1L << config.sparc_SHA512) != 0) { features.add(CPUFeature.SHA512); } if ((config.vmVersionFeatures & 1L << config.sparc_SPARC5) != 0) { features.add(CPUFeature.SPARC5); } + if ((config.vmVersionFeatures & 1L << config.sparc_SPARC5B) != 0) { + features.add(CPUFeature.SPARC5B); + } + if ((config.vmVersionFeatures & 1L << config.sparc_SPARC6) != 0) { + features.add(CPUFeature.SPARC6); + } if ((config.vmVersionFeatures & 1L << config.sparc_V9) != 0) { features.add(CPUFeature.V9); } @@ -142,6 +163,9 @@ public class SPARCHotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFacto if ((config.vmVersionFeatures & 1L << config.sparc_VIS3B) != 0) { features.add(CPUFeature.VIS3B); } + if ((config.vmVersionFeatures & 1L << config.sparc_VIS3C) != 0) { + features.add(CPUFeature.VIS3C); + } if ((config.vmVersionFeatures & 1L << config.sparc_XMONT) != 0) { features.add(CPUFeature.XMONT); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotVMConfig.java index a5ae1d85eef..e1b441cadb8 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotVMConfig.java @@ -55,27 +55,35 @@ class SPARCHotSpotVMConfig extends HotSpotVMConfigAccess { final int sparc_CBCOND = getConstant("VM_Version::ISA_CBCOND", Integer.class); final int sparc_CRC32C = getConstant("VM_Version::ISA_CRC32C", Integer.class); final int sparc_DES = getConstant("VM_Version::ISA_DES", Integer.class); + final int sparc_DICTUNP = getConstant("VM_Version::ISA_DICTUNP", Integer.class); final int sparc_FMAF = getConstant("VM_Version::ISA_FMAF", Integer.class); + final int sparc_FPCMPSHL = getConstant("VM_Version::ISA_FPCMPSHL", Integer.class); final int sparc_HPC = getConstant("VM_Version::ISA_HPC", Integer.class); final int sparc_IMA = getConstant("VM_Version::ISA_IMA", Integer.class); final int sparc_KASUMI = getConstant("VM_Version::ISA_KASUMI", Integer.class); final int sparc_MD5 = getConstant("VM_Version::ISA_MD5", Integer.class); + final int sparc_MME = getConstant("VM_Version::ISA_MME", Integer.class); final int sparc_MONT = getConstant("VM_Version::ISA_MONT", Integer.class); final int sparc_MPMUL = getConstant("VM_Version::ISA_MPMUL", Integer.class); final int sparc_MWAIT = getConstant("VM_Version::ISA_MWAIT", Integer.class); final int sparc_PAUSE = getConstant("VM_Version::ISA_PAUSE", Integer.class); final int sparc_PAUSE_NSEC = getConstant("VM_Version::ISA_PAUSE_NSEC", Integer.class); final int sparc_POPC = getConstant("VM_Version::ISA_POPC", Integer.class); + final int sparc_RLE = getConstant("VM_Version::ISA_RLE", Integer.class); final int sparc_SHA1 = getConstant("VM_Version::ISA_SHA1", Integer.class); final int sparc_SHA256 = getConstant("VM_Version::ISA_SHA256", Integer.class); + final int sparc_SHA3 = getConstant("VM_Version::ISA_SHA3", Integer.class); final int sparc_SHA512 = getConstant("VM_Version::ISA_SHA512", Integer.class); final int sparc_SPARC5 = getConstant("VM_Version::ISA_SPARC5", Integer.class); + final int sparc_SPARC5B = getConstant("VM_Version::ISA_SPARC5B", Integer.class); + final int sparc_SPARC6 = getConstant("VM_Version::ISA_SPARC6", Integer.class); final int sparc_V9 = getConstant("VM_Version::ISA_V9", Integer.class); final int sparc_VAMASK = getConstant("VM_Version::ISA_VAMASK", Integer.class); final int sparc_VIS1 = getConstant("VM_Version::ISA_VIS1", Integer.class); final int sparc_VIS2 = getConstant("VM_Version::ISA_VIS2", Integer.class); final int sparc_VIS3 = getConstant("VM_Version::ISA_VIS3", Integer.class); final int sparc_VIS3B = getConstant("VM_Version::ISA_VIS3B", Integer.class); + final int sparc_VIS3C = getConstant("VM_Version::ISA_VIS3C", Integer.class); final int sparc_XMONT = getConstant("VM_Version::ISA_XMONT", Integer.class); final int sparc_XMPMUL = getConstant("VM_Version::ISA_XMPMUL", Integer.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java index 2a907751b7a..979ee934df5 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -255,6 +255,15 @@ final class CompilerToVM { */ native void resolveInvokeHandleInPool(HotSpotConstantPool constantPool, int cpi); + /** + * If {@code cpi} denotes an entry representing a resolved dynamic adapter + * (see {@code resolveInvokeDynamicInPool} and {@code resolveInvokeHandleInPool}), + * return the opcode of the instruction for which the resolution was performed + * ({@code invokedynamic} or {@code invokevirtual}}, or {@code -1} otherwise. + */ + native int isResolvedInvokeHandleInPool(HotSpotConstantPool constantPool, int cpi); + + /** * Gets the list of type names (in the format of {@link JavaType#getName()}) denoting the * classes that define signature polymorphic methods. diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java index d88a8468e73..8f014b91e9c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -42,7 +42,7 @@ import jdk.vm.ci.meta.Signature; /** * Implementation of {@link ConstantPool} for HotSpot. */ -final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject { +public final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject { /** * Subset of JVM bytecode opcodes used by {@link HotSpotConstantPool}. @@ -215,14 +215,14 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject } /** - * Converts a raw index from the bytecodes to a constant pool index by adding a + * Converts a raw index from the bytecodes to a constant pool cache index by adding a * {@link HotSpotVMConfig#constantPoolCpCacheIndexTag constant}. * * @param rawIndex index from the bytecode * @param opcode bytecode to convert the index for - * @return constant pool index + * @return constant pool cache index */ - private static int rawIndexToConstantPoolIndex(int rawIndex, int opcode) { + private static int rawIndexToConstantPoolCacheIndex(int rawIndex, int opcode) { int index; if (opcode == Bytecodes.INVOKEDYNAMIC) { index = rawIndex; @@ -271,6 +271,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject return metaspaceConstantPool; } + @Override public long getMetaspacePointer() { return getMetaspaceConstantPool(); } @@ -541,7 +542,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject @Override public JavaConstant lookupAppendix(int cpi, int opcode) { assert Bytecodes.isInvoke(opcode); - final int index = rawIndexToConstantPoolIndex(cpi, opcode); + final int index = rawIndexToConstantPoolCacheIndex(cpi, opcode); Object appendix = compilerToVM().lookupAppendixInPool(this, index); if (appendix == null) { return null; @@ -566,7 +567,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject @Override public JavaMethod lookupMethod(int cpi, int opcode) { - final int index = rawIndexToConstantPoolIndex(cpi, opcode); + final int index = rawIndexToConstantPoolCacheIndex(cpi, opcode); final HotSpotResolvedJavaMethod method = compilerToVM().lookupMethodInPool(this, index, (byte) opcode); if (method != null) { return method; @@ -603,7 +604,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject @Override public JavaField lookupField(int cpi, ResolvedJavaMethod method, int opcode) { - final int index = rawIndexToConstantPoolIndex(cpi, opcode); + final int index = rawIndexToConstantPoolCacheIndex(cpi, opcode); final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index); final int typeIndex = getSignatureRefIndexAt(nameAndTypeIndex); String typeName = lookupUtf8(typeIndex); @@ -634,6 +635,25 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject } } + /* + * Converts a raw index from the bytecodes to a constant pool index + * (not a cache index). + * + * @param rawIndex index from the bytecode + * @param opcode bytecode to convert the index for + * @return constant pool index + */ + public int rawIndexToConstantPoolIndex(int index, int opcode) { + if (isInvokedynamicIndex(index)) { + assert opcode == Bytecodes.INVOKEDYNAMIC; + index = decodeInvokedynamicIndex(index) + config().constantPoolCpCacheIndexTag; + } else { + assert opcode != Bytecodes.INVOKEDYNAMIC; + index = rawIndexToConstantPoolCacheIndex(index, opcode); + } + return compilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); + } + @Override @SuppressWarnings("fallthrough") public void loadReferencedType(int cpi, int opcode) { @@ -664,7 +684,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject case Bytecodes.INVOKESTATIC: case Bytecodes.INVOKEINTERFACE: { // invoke and field instructions point to a constant pool cache entry. - index = rawIndexToConstantPoolIndex(cpi, opcode); + index = rawIndexToConstantPoolCacheIndex(cpi, opcode); index = compilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); break; } @@ -696,7 +716,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject } if (tag == JVM_CONSTANT.MethodRef) { if (Bytecodes.isInvokeHandleAlias(opcode) && isSignaturePolymorphicHolder(type)) { - final int methodRefCacheIndex = rawIndexToConstantPoolIndex(cpi, opcode); + final int methodRefCacheIndex = rawIndexToConstantPoolCacheIndex(cpi, opcode); assert checkTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), JVM_CONSTANT.MethodRef); compilerToVM().resolveInvokeHandleInPool(this, methodRefCacheIndex); } @@ -734,6 +754,25 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject return false; } + /** + * Check for a resolved dynamic adapter method at the specified index, + * resulting from either a resolved invokedynamic or invokevirtual on a signature polymorphic + * MethodHandle method (HotSpot invokehandle). + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed + * @return {@code true} if a signature polymorphic method reference was found, otherwise {@code false} + */ + public boolean isResolvedDynamicInvoke(int cpi, int opcode) { + if (Bytecodes.isInvokeHandleAlias(opcode)) { + final int methodRefCacheIndex = rawIndexToConstantPoolCacheIndex(cpi, opcode); + assert checkTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), JVM_CONSTANT.MethodRef); + int op = compilerToVM().isResolvedInvokeHandleInPool(this, methodRefCacheIndex); + return op == opcode; + } + return false; + } + @Override public String toString() { HotSpotResolvedObjectType holder = getHolder(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPoolObject.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPoolObject.java new file mode 100644 index 00000000000..0cd05a37839 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPoolObject.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017, 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.vm.ci.hotspot; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Represents a constant that was retrieved from a constant pool. + * Used to keep track of the constant pool slot for the constant. + */ +public final class HotSpotConstantPoolObject extends HotSpotObjectConstantImpl { + + static JavaConstant forObject(HotSpotResolvedObjectType type, int cpi, Object object) { + return new HotSpotConstantPoolObject(type, cpi, object); + } + + public static JavaConstant forObject(HotSpotResolvedObjectType type, int cpi, JavaConstant object) { + return forObject(type, cpi, ((HotSpotObjectConstantImpl)object).object()); + } + + private final HotSpotResolvedObjectType type; + private final int cpi; + + public HotSpotResolvedObjectType getCpType() { return type; } + public int getCpi() { return cpi; } + + HotSpotConstantPoolObject(HotSpotResolvedObjectType type, int cpi, Object object) { + super(object, false); + this.type = type; + this.cpi = cpi; + } + + @Override + public boolean equals(Object o) { + if (o instanceof HotSpotConstantPoolObject) { + if (super.equals(o)) { + HotSpotConstantPoolObject other = (HotSpotConstantPoolObject) o; + return type == other.type && cpi == other.cpi; + } + } + return false; + } + + @Override + public String toValueString() { + return getCpType().getName() + getCpi(); + } + + @Override + public String toString() { + return super.toString() + "@" + toValueString(); + } + +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java index e3ad9c834c2..feae2a72267 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -138,21 +138,6 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider { return true; } - private boolean isValidObjectFieldDisplacement(Constant base, long displacement) { - if (base instanceof HotSpotMetaspaceConstant) { - MetaspaceWrapperObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); - if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { - if (displacement == runtime.getConfig().classMirrorOffset) { - // Klass::_java_mirror is valid for all Klass* values - return true; - } - } else { - throw new IllegalArgumentException(String.valueOf(metaspaceObject)); - } - } - return false; - } - private static long asRawPointer(Constant base) { if (base instanceof HotSpotMetaspaceConstantImpl) { MetaspaceWrapperObject meta = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); @@ -202,7 +187,7 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider { if (base instanceof HotSpotMetaspaceConstant) { MetaspaceWrapperObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { - if (displacement == runtime.getConfig().classMirrorOffset) { + if (displacement == runtime.getConfig().classMirrorHandleOffset) { assert expected == ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror(); } } @@ -294,10 +279,18 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider { Object o = readRawObject(base, displacement, runtime.getConfig().useCompressedOops); return HotSpotObjectConstantImpl.forObject(o); } - if (!isValidObjectFieldDisplacement(base, displacement)) { - return null; + if (base instanceof HotSpotMetaspaceConstant) { + MetaspaceWrapperObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); + if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { + if (displacement == runtime.getConfig().classMirrorHandleOffset) { + // Klass::_java_mirror is valid for all Klass* values + return HotSpotObjectConstantImpl.forObject(((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror()); + } + } else { + throw new IllegalArgumentException(String.valueOf(metaspaceObject)); + } } - return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, false)); + return null; } @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java index 5bd5014cdd8..259cf070840 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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 @@ -32,7 +32,7 @@ public class HotSpotMetaData { private byte[] relocBytes; private byte[] exceptionBytes; private byte[] oopMaps; - private String[] metadata; + private Object[] metadata; public HotSpotMetaData(TargetDescription target, HotSpotCompiledCode compiledMethod) { // Assign the fields default values... @@ -66,7 +66,7 @@ public class HotSpotMetaData { return oopMaps; } - public String[] metadataEntries() { + public Object[] metadataEntries() { return metadata; } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java index ddc7331b28f..04d899dafd9 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java @@ -578,6 +578,13 @@ final class HotSpotMethodData { } totalCount += getMethodsNotRecordedExecutionCount(data, position); + + // Fixup the case of C1's inability to optimize profiling of a statically bindable call site. + // If it's a monomorphic call site, attribute all the counts to the first type (if any is recorded). + if (entries == 1) { + counts[0] = totalCount; + } + return new RawItemProfile<>(entries, methods, counts, totalCount); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java index ac884676d52..83706952e10 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, 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 @@ -38,7 +38,7 @@ import jdk.vm.ci.meta.ResolvedJavaType; * Represents a constant non-{@code null} object reference, within the compiler and across the * compiler/runtime interface. */ -final class HotSpotObjectConstantImpl implements HotSpotObjectConstant { +class HotSpotObjectConstantImpl implements HotSpotObjectConstant { static JavaConstant forObject(Object object) { return forObject(object, false); @@ -73,7 +73,7 @@ final class HotSpotObjectConstantImpl implements HotSpotObjectConstant { private final Object object; private final boolean compressed; - private HotSpotObjectConstantImpl(Object object, boolean compressed) { + protected HotSpotObjectConstantImpl(Object object, boolean compressed) { this.object = object; this.compressed = compressed; assert object != null; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java index 5a71dd513de..398f6241717 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -122,4 +122,6 @@ public interface HotSpotResolvedJavaMethod extends ResolvedJavaMethod { int allocateCompileId(int entryBCI); boolean hasCodeAtLevel(int entryBCI, int level); + + int methodIdnum(); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 51b556ae038..6fb8ce8a6fa 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -777,4 +777,8 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp } return compilerToVM().hasCompiledCodeForOSR(this, entryBCI, level); } + + public int methodIdnum() { + return UNSAFE.getChar(getConstMethod() + config().constMethodMethodIdnumOffset); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java index 9028194e0df..a0c757bbc37 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -108,4 +108,7 @@ public interface HotSpotResolvedObjectType extends ResolvedJavaType { HotSpotResolvedObjectType getEnclosingType(); ResolvedJavaMethod getClassInitializer(); + + boolean isAnonymous(); + } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 3b424770ca1..abb3e43998d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -934,4 +934,13 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem public boolean isCloneableWithAllocation() { return (getAccessFlags() & config().jvmAccIsCloneableFast) != 0; } + + private int getMiscFlags() { + return UNSAFE.getInt(getMetaspaceKlass() + config().instanceKlassMiscFlagsOffset); + } + + public boolean isAnonymous() { + return (getMiscFlags() & config().instanceKlassMiscIsAnonymous) != 0; + } + } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 25f6153f54e..640422e8605 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -77,7 +77,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { /** * The offset of the _java_mirror field (of type {@link Class}) in a Klass. */ - final int classMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "oop"); + final int classMirrorHandleOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle"); final int klassAccessFlagsOffset = getFieldOffset("Klass::_access_flags", Integer.class, "AccessFlags"); final int klassLayoutHelperOffset = getFieldOffset("Klass::_layout_helper", Integer.class, "jint"); @@ -92,11 +92,13 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "u1"); final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*"); final int instanceKlassFieldsOffset = getFieldOffset("InstanceKlass::_fields", Integer.class, "Array*"); + final int instanceKlassMiscFlagsOffset = getFieldOffset("InstanceKlass::_misc_flags", Integer.class, "u2"); final int klassVtableStartOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_start_offset", Integer.class, "int"); final int klassVtableLengthOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_length_offset", Integer.class, "int"); final int instanceKlassStateLinked = getConstant("InstanceKlass::linked", Integer.class); final int instanceKlassStateFullyInitialized = getConstant("InstanceKlass::fully_initialized", Integer.class); + final int instanceKlassMiscIsAnonymous = getConstant("InstanceKlass::_misc_is_anonymous", Integer.class); final int arrayU1LengthOffset = getFieldOffset("Array::_length", Integer.class, "int"); final int arrayU1DataOffset = getFieldOffset("Array::_data", Integer.class); @@ -185,6 +187,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { final int constMethodCodeSizeOffset = getFieldOffset("ConstMethod::_code_size", Integer.class, "u2"); final int constMethodNameIndexOffset = getFieldOffset("ConstMethod::_name_index", Integer.class, "u2"); final int constMethodSignatureIndexOffset = getFieldOffset("ConstMethod::_signature_index", Integer.class, "u2"); + final int constMethodMethodIdnumOffset = getFieldOffset("ConstMethod::_method_idnum", Integer.class, "u2"); final int constMethodMaxStackOffset = getFieldOffset("ConstMethod::_max_stack", Integer.class, "u2"); final int methodMaxLocalsOffset = getFieldOffset("ConstMethod::_max_locals", Integer.class, "u2"); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java index ee40d426346..29dd0fb4d36 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java @@ -344,27 +344,35 @@ public class SPARC extends Architecture { CBCOND, CRC32C, DES, + DICTUNP, FMAF, + FPCMPSHL, HPC, IMA, KASUMI, MD5, + MME, MONT, MPMUL, MWAIT, PAUSE, PAUSE_NSEC, POPC, + RLE, SHA1, SHA256, + SHA3, SHA512, SPARC5, + SPARC5B, + SPARC6, V9, VAMASK, VIS1, VIS2, VIS3, VIS3B, + VIS3C, XMONT, XMPMUL, // Synthesised CPU properties: diff --git a/src/jdk.internal.vm.ci/share/classes/module-info.java b/src/jdk.internal.vm.ci/share/classes/module-info.java index e6001b18f37..fca5828dd06 100644 --- a/src/jdk.internal.vm.ci/share/classes/module-info.java +++ b/src/jdk.internal.vm.ci/share/classes/module-info.java @@ -25,6 +25,9 @@ module jdk.internal.vm.ci { exports jdk.vm.ci.services to jdk.internal.vm.compiler; + exports jdk.vm.ci.runtime to + jdk.internal.vm.compiler, + jdk.internal.vm.compiler.management; uses jdk.vm.ci.services.JVMCIServiceLocator; uses jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory; diff --git a/src/jdk.internal.vm.compiler.management/share/classes/module-info.java b/src/jdk.internal.vm.compiler.management/share/classes/module-info.java new file mode 100644 index 00000000000..328648d4456 --- /dev/null +++ b/src/jdk.internal.vm.compiler.management/share/classes/module-info.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017, 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. + */ + +/** + * Registers Graal Compiler specific management interfaces for the JVM. + * + * @moduleGraph + * @since 10 + */ +module jdk.internal.vm.compiler.management { + requires java.management; + requires jdk.management; + requires jdk.internal.vm.ci; + requires jdk.internal.vm.compiler; + + provides sun.management.spi.PlatformMBeanProvider with + org.graalvm.compiler.hotspot.jmx.GraalMBeans; +} + diff --git a/src/jdk.internal.vm.compiler.management/share/classes/org/graalvm/compiler/hotspot/jmx/GraalMBeans.java b/src/jdk.internal.vm.compiler.management/share/classes/org/graalvm/compiler/hotspot/jmx/GraalMBeans.java new file mode 100644 index 00000000000..0161f92a216 --- /dev/null +++ b/src/jdk.internal.vm.compiler.management/share/classes/org/graalvm/compiler/hotspot/jmx/GraalMBeans.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.jmx; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import jdk.vm.ci.runtime.JVMCI; +import jdk.vm.ci.runtime.JVMCICompiler; +import jdk.vm.ci.runtime.JVMCIRuntime; +import org.graalvm.compiler.hotspot.HotSpotGraalCompiler; +import sun.management.spi.PlatformMBeanProvider; +import sun.management.spi.PlatformMBeanProvider.PlatformComponent; + +public final class GraalMBeans extends PlatformMBeanProvider { + @Override + public List> getPlatformComponentList() { + List> components = new ArrayList<>(); + try { + Object bean = findGraalRuntimeBean(); + if (bean != null) { + components.add(new HotSpotRuntimeMBeanComponent(bean)); + } + } catch (InternalError | LinkageError err) { + // go on and ignore + } + return components; + } + + public static Object findGraalRuntimeBean() { + JVMCIRuntime r = JVMCI.getRuntime(); + JVMCICompiler c = r.getCompiler(); + if (c instanceof HotSpotGraalCompiler) { + return ((HotSpotGraalCompiler) c).mbean(); + } + return null; + } + + private static final class HotSpotRuntimeMBeanComponent implements PlatformComponent { + + private final String name; + private final Object mbean; + + HotSpotRuntimeMBeanComponent(Object mbean) { + this.name = "org.graalvm.compiler.hotspot:type=Options"; + this.mbean = mbean; + } + + @Override + public Set> mbeanInterfaces() { + return Collections.emptySet(); + } + + @Override + public Set mbeanInterfaceNames() { + return Collections.emptySet(); + } + + @Override + public String getObjectNamePattern() { + return name; + } + + @Override + public Map nameToMBeanMap() { + return Collections.singletonMap(name, mbean); + } + } +} diff --git a/src/jdk.internal.vm.compiler/.mx.graal/suite.py b/src/jdk.internal.vm.compiler/.mx.graal/suite.py index 6dd8b072ee2..e8df78c52c0 100644 --- a/src/jdk.internal.vm.compiler/.mx.graal/suite.py +++ b/src/jdk.internal.vm.compiler/.mx.graal/suite.py @@ -6,7 +6,7 @@ suite = { # This puts mx/ as a sibling of the JDK build configuration directories # (e.g., macosx-x86_64-normal-server-release). - "outputRoot" : "../../../build/mx/hotspot", + "outputRoot" : "../../build/mx/hotspot", "jdklibraries" : { "JVMCI_SERVICES" : { @@ -1093,7 +1093,7 @@ suite = { }, "jdk.tools.jaotc.test" : { - "subDir" : "../../test/compiler/aot", + "subDir" : "../../test/hotspot/jtreg/compiler/aot", "sourceDirs" : ["src"], "dependencies" : [ "mx:JUNIT", diff --git a/src/jdk.internal.vm.compiler/share/classes/module-info.java b/src/jdk.internal.vm.compiler/share/classes/module-info.java index 0cae4bc22d9..44c1259646d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/module-info.java +++ b/src/jdk.internal.vm.compiler/share/classes/module-info.java @@ -50,7 +50,9 @@ module jdk.internal.vm.compiler { exports org.graalvm.compiler.core.target to jdk.aot; exports org.graalvm.compiler.debug to jdk.aot; exports org.graalvm.compiler.graph to jdk.aot; - exports org.graalvm.compiler.hotspot to jdk.aot; + exports org.graalvm.compiler.hotspot to + jdk.aot, + jdk.internal.vm.compiler.management; exports org.graalvm.compiler.hotspot.meta to jdk.aot; exports org.graalvm.compiler.hotspot.replacements to jdk.aot; exports org.graalvm.compiler.hotspot.stubs to jdk.aot; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java index b7f3a279f63..41325e230e9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java @@ -253,13 +253,17 @@ public final class ComputeBlockOrder { * Comparator for sorting blocks based on loop depth and probability. */ private static class BlockOrderComparator> implements Comparator { + private static final double EPSILON = 1E-6; @Override public int compare(T a, T b) { - // Loop blocks before any loop exit block. - int diff = b.getLoopDepth() - a.getLoopDepth(); - if (diff != 0) { - return diff; + // Loop blocks before any loop exit block. The only exception are blocks that are + // (almost) impossible to reach. + if (a.probability() > EPSILON && b.probability() > EPSILON) { + int diff = b.getLoopDepth() - a.getLoopDepth(); + if (diff != 0) { + return diff; + } } // Blocks with high probability before blocks with low probability. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java index 1b932aa68d8..10f0a91e853 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java @@ -172,7 +172,7 @@ public class CheckGraalInvariants extends GraalCompilerTest { PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java index 2c0a9432b98..00887afda2a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java @@ -1249,7 +1249,7 @@ public abstract class GraalCompilerTest extends GraalTest { } protected PhaseSuite getEagerGraphBuilderSuite() { - return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true)); + return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true)); } /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashMapGetTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashMapGetTest.java new file mode 100644 index 00000000000..1e0001ebd5e --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashMapGetTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.compiler.core.test; + +import jdk.vm.ci.meta.ResolvedJavaMethod; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; +import org.junit.Test; + +import java.util.HashMap; + +public class HashMapGetTest extends GraalCompilerTest { + + public static void mapGet(HashMap map, Integer key) { + map.get(key); + } + + @Test + public void hashMapTest() { + HashMap map = new HashMap<>(); + ResolvedJavaMethod get = getResolvedJavaMethod(HashMapGetTest.class, "mapGet"); + for (int i = 0; i < 5000; i++) { + mapGet(map, i); + map.put(i, i); + mapGet(map, i); + } + test(get, null, map, new Integer(0)); + for (IfNode ifNode : lastCompiledGraph.getNodes(IfNode.TYPE)) { + LogicNode condition = ifNode.condition(); + if (ifNode.getTrueSuccessorProbability() < 0.4 && condition instanceof ObjectEqualsNode) { + assertTrue(ifNode.trueSuccessor().next() instanceof ReturnNode, "Expected return.", ifNode.trueSuccessor(), ifNode.trueSuccessor().next()); + } + } + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OffHeapUnsafeAccessTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OffHeapUnsafeAccessTest.java new file mode 100644 index 00000000000..d10ed2f2476 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OffHeapUnsafeAccessTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.core.test; + +import java.lang.reflect.Field; + +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.junit.Assert; +import org.junit.Test; + +import jdk.vm.ci.meta.JavaKind; +import sun.misc.Unsafe; + +/** + * Tests that off-heap memory writes don't prevent optimization of on-heap accesses. + */ +public class OffHeapUnsafeAccessTest extends GraalCompilerTest { + + static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + // Fast path when we are trusted. + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + // Slow path when we are not trusted. + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } + + public byte unboxByteAndStore(long memory, byte[] box) { + byte val = box[0]; + UNSAFE.putByte(memory, val); + UNSAFE.putByte(null, memory, val); + return box[0]; + } + + public char unboxCharAndStore(long memory, char[] box) { + char val = box[0]; + UNSAFE.putChar(memory, val); + UNSAFE.putChar(null, memory, val); + return box[0]; + } + + public int unboxIntAndStore(long memory, int[] box) { + int val = box[0]; + UNSAFE.putInt(memory, val); + UNSAFE.putInt(null, memory, val); + return box[0]; + } + + public long unboxLongAndStore(long memory, long[] box) { + long val = box[0]; + UNSAFE.putLong(memory, val); + UNSAFE.putLong(null, memory, val); + UNSAFE.putAddress(memory, val); + return box[0]; + } + + public float unboxFloatAndStore(long memory, float[] box) { + float val = box[0]; + UNSAFE.putFloat(memory, val); + UNSAFE.putFloat(null, memory, val); + return box[0]; + } + + public double unboxDoubleAndStore(long memory, double[] box) { + double val = box[0]; + UNSAFE.putDouble(memory, val); + UNSAFE.putDouble(null, memory, val); + return box[0]; + } + + private void assertExactlyOneArrayLoad(JavaKind elementKind) { + int total = 0; + for (ReadNode read : lastCompiledGraph.getNodes().filter(ReadNode.class)) { + if (read.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind))) { + total++; + } + } + Assert.assertEquals(1, total); + } + + @Test + public void testGet() { + long buf = allocBuf(); + if (buf != 0) { + try { + test("unboxByteAndStore", buf, new byte[]{40}); + assertExactlyOneArrayLoad(JavaKind.Byte); + + test("unboxCharAndStore", buf, new char[]{41}); + assertExactlyOneArrayLoad(JavaKind.Char); + + test("unboxIntAndStore", buf, new int[]{42}); + assertExactlyOneArrayLoad(JavaKind.Int); + + test("unboxLongAndStore", buf, new long[]{43}); + assertExactlyOneArrayLoad(JavaKind.Long); + + test("unboxFloatAndStore", buf, new float[]{44.0F}); + assertExactlyOneArrayLoad(JavaKind.Float); + + test("unboxDoubleAndStore", buf, new double[]{45.0D}); + assertExactlyOneArrayLoad(JavaKind.Double); + } finally { + UNSAFE.freeMemory(buf); + } + } + } + + protected long allocBuf() { + try { + return UNSAFE.allocateMemory(16); + } catch (OutOfMemoryError e) { + return 0L; + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java new file mode 100644 index 00000000000..342cbe3aa30 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.core.test; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.options.OptionValues; +import org.junit.Assume; +import org.junit.Test; + +public class StableArrayReadFoldingTest extends GraalCompilerTest { + + static final boolean[] STABLE_BOOLEAN_ARRAY = new boolean[16]; + static final int[] STABLE_INT_ARRAY = new int[16]; + + static final long BOOLEAN_ARRAY_BASE_OFFSET; + static final long INT_ARRAY_BASE_OFFSET; + + static { + BOOLEAN_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(boolean[].class); + INT_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(int[].class); + } + + @Override + protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId, OptionValues options) { + StructuredGraph graph = super.parseForCompile(method, compilationId, options); + // Mimic @Stable array constants. + for (ConstantNode constantNode : graph.getNodes().filter(ConstantNode.class).snapshot()) { + if (getConstantReflection().readArrayLength(constantNode.asJavaConstant()) != null) { + ConstantNode newConstantNode = graph.unique(ConstantNode.forConstant(constantNode.asJavaConstant(), 1, true, getMetaAccess())); + constantNode.replaceAndDelete(newConstantNode); + } + } + return graph; + } + + public static boolean killWithSameType() { + boolean beforeKill = UNSAFE.getBoolean(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET); + STABLE_BOOLEAN_ARRAY[0] = true; + boolean afterKill = UNSAFE.getBoolean(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET); + + STABLE_BOOLEAN_ARRAY[0] = false; + return beforeKill == afterKill; + } + + @Test + public void testKillWithSameType() { + ResolvedJavaMethod method = getResolvedJavaMethod("killWithSameType"); + testAgainstExpected(method, new Result(true, null), null); + } + + public static boolean killWithDifferentType() { + byte beforeKill = UNSAFE.getByte(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET); + STABLE_BOOLEAN_ARRAY[0] = true; + byte afterKill = UNSAFE.getByte(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET); + + STABLE_BOOLEAN_ARRAY[0] = false; + return beforeKill == afterKill; + } + + @Test + public void testKillWithDifferentType() { + ResolvedJavaMethod method = getResolvedJavaMethod("killWithDifferentType"); + testAgainstExpected(method, new Result(true, null), null); + } + + public static boolean killWithSameTypeUnaligned() { + int beforeKill = UNSAFE.getInt(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1); + STABLE_INT_ARRAY[0] = 0x01020304; + int afterKill = UNSAFE.getInt(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1); + + STABLE_INT_ARRAY[0] = 0; + return beforeKill == afterKill; + } + + @Test + public void testKillWithSameTypeUnaligned() { + Assume.assumeTrue("Only test unaligned access on AMD64", getTarget().arch instanceof AMD64); + ResolvedJavaMethod method = getResolvedJavaMethod("killWithSameTypeUnaligned"); + testAgainstExpected(method, new Result(true, null), null); + } + + public static boolean killWithDifferentTypeUnaligned() { + byte beforeKill = UNSAFE.getByte(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1); + STABLE_INT_ARRAY[0] = 0x01020304; + byte afterKill = UNSAFE.getByte(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1); + + STABLE_INT_ARRAY[0] = 0; + return beforeKill == afterKill; + } + + @Test + public void testKillWithDifferentTypeUnaligned() { + Assume.assumeTrue("Only test unaligned access on AMD64", getTarget().arch instanceof AMD64); + ResolvedJavaMethod method = getResolvedJavaMethod("killWithDifferentTypeUnaligned"); + testAgainstExpected(method, new Result(true, null), null); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java index 866b2f8328a..e6063bfc9d5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java @@ -82,7 +82,7 @@ public class StaticInterfaceFieldTest extends GraalTest { PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java index a5762cd4f0a..c7825439a07 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java @@ -89,7 +89,7 @@ public class UnbalancedMonitorsTest extends GraalCompilerTest { OptionValues options = getInitialOptions(); StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options)).method(method).build(); Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE; GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), null, null, graphBuilderConfig, optimisticOpts, null); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java index 96471806658..b8db3623752 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java @@ -46,11 +46,13 @@ public class UnsafeReadEliminationTest extends GraalCompilerTest { public static double SideEffectD; public static double SideEffectL; + private static final long booleanArrayBaseOffset; private static final long byteArrayBaseOffset; private static final long intArrayBaseOffset; private static final long longArrayBaseOffset; static { + booleanArrayBaseOffset = UNSAFE.arrayBaseOffset(boolean[].class); byteArrayBaseOffset = UNSAFE.arrayBaseOffset(byte[].class); intArrayBaseOffset = UNSAFE.arrayBaseOffset(int[].class); longArrayBaseOffset = UNSAFE.arrayBaseOffset(long[].class); @@ -212,4 +214,77 @@ public class UnsafeReadEliminationTest extends GraalCompilerTest { test("testWriteFloatToIntArraySnippet"); } + public static final byte[] FINAL_BYTE_ARRAY = new byte[16]; + + public static boolean alignedKill() { + int beforeKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset); + FINAL_BYTE_ARRAY[0] = 1; + int afterKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset); + + FINAL_BYTE_ARRAY[0] = 0; // reset + return beforeKill == afterKill; + } + + @Test + public void testAlignedKill() { + test("alignedKill"); + } + + public static boolean unalignedKill() { + int beforeKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset); + FINAL_BYTE_ARRAY[1] = 1; + int afterKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset); + + FINAL_BYTE_ARRAY[1] = 0; // reset + return beforeKill == afterKill; + } + + @Test + public void testUnalignedKill() { + test("unalignedKill"); + } + + public static final boolean[] FINAL_BOOLEAN_ARRAY = new boolean[16]; + + public static boolean killBooleanAccessToBooleanArrayViaBASTORE() { + boolean beforeKill = UNSAFE.getBoolean(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset); + FINAL_BOOLEAN_ARRAY[0] = true; + boolean afterKill = UNSAFE.getBoolean(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset); + + FINAL_BOOLEAN_ARRAY[0] = false; // reset + return beforeKill == afterKill; + } + + @Test + public void testKillBooleanAccessToBooleanArrayViaBASTORE() { + test("killBooleanAccessToBooleanArrayViaBASTORE"); + } + + public static boolean killByteAccessToBooleanArrayViaBASTORE() { + byte beforeKill = UNSAFE.getByte(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset); + FINAL_BOOLEAN_ARRAY[0] = true; + byte afterKill = UNSAFE.getByte(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset); + + FINAL_BOOLEAN_ARRAY[0] = false; // reset + return beforeKill == afterKill; + } + + @Test + public void testKillByteAccessToBooleanArrayViaBASTORE() { + test("killByteAccessToBooleanArrayViaBASTORE"); + } + + public static boolean unsafeWriteToBooleanArray() { + UNSAFE.putByte(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset, (byte) 2); + boolean result = UNSAFE.getBoolean(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset); + + FINAL_BOOLEAN_ARRAY[0] = false; // reset + return result; + } + + @Test + public void testUnsafeWriteToBooleanArray() { + test("unsafeWriteToBooleanArray"); + } + } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java index 809089fb8d1..1cecbfd10c1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java @@ -123,7 +123,7 @@ public class VerifyBailoutUsageTest { MetaAccessProvider metaAccess = providers.getMetaAccess(); PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = getInitialOptions(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java index ae3de81dc20..22299520dad 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java @@ -344,7 +344,7 @@ public class VerifyDebugUsageTest { MetaAccessProvider metaAccess = providers.getMetaAccess(); PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = getInitialOptions(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java index c3d2e33397a..ca105276a1c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java @@ -268,7 +268,7 @@ public class VerifyVirtualizableTest { MetaAccessProvider metaAccess = providers.getMetaAccess(); PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = getInitialOptions(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java index c42c6f001d3..2bc269bd533 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.core.test.ea; +import org.graalvm.compiler.core.test.GraalCompilerTest; import org.junit.Test; import sun.misc.Unsafe; @@ -36,7 +37,7 @@ import org.graalvm.compiler.phases.common.inlining.InliningPhase; import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; -public class PEAReadEliminationTest extends EarlyReadEliminationTest { +public class PEAReadEliminationTest extends GraalCompilerTest { public static int testIndexed1Snippet(int[] array) { array[1] = 1; @@ -50,7 +51,7 @@ public class PEAReadEliminationTest extends EarlyReadEliminationTest { @Test public void testIndexed1() { - StructuredGraph graph = processMethod("testIndexed1Snippet", false); + StructuredGraph graph = processMethod("testIndexed1Snippet"); assertDeepEquals(0, graph.getNodes().filter(LoadIndexedNode.class).count()); } @@ -70,7 +71,7 @@ public class PEAReadEliminationTest extends EarlyReadEliminationTest { @Test public void testIndexed2() { - StructuredGraph graph = processMethod("testIndexed2Snippet", false); + StructuredGraph graph = processMethod("testIndexed2Snippet"); assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count()); assertDeepEquals(7, graph.getNodes().filter(StoreIndexedNode.class).count()); } @@ -94,7 +95,7 @@ public class PEAReadEliminationTest extends EarlyReadEliminationTest { @Test public void testIndexed3() { - StructuredGraph graph = processMethod("testIndexed3Snippet", false); + StructuredGraph graph = processMethod("testIndexed3Snippet"); assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count()); } @@ -113,7 +114,7 @@ public class PEAReadEliminationTest extends EarlyReadEliminationTest { @Test public void testIndexed4() { - StructuredGraph graph = processMethod("testIndexed4Snippet", false); + StructuredGraph graph = processMethod("testIndexed4Snippet"); assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count()); } @@ -129,7 +130,7 @@ public class PEAReadEliminationTest extends EarlyReadEliminationTest { @Test public void testUnsafe1() { - StructuredGraph graph = processMethod("testUnsafe1Snippet", false); + StructuredGraph graph = processMethod("testUnsafe1Snippet"); assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count()); } @@ -142,7 +143,7 @@ public class PEAReadEliminationTest extends EarlyReadEliminationTest { @Test public void testUnsafe2() { - StructuredGraph graph = processMethod("testUnsafe2Snippet", false); + StructuredGraph graph = processMethod("testUnsafe2Snippet"); assertDeepEquals(3, graph.getNodes().filter(RawLoadNode.class).count()); } @@ -158,7 +159,7 @@ public class PEAReadEliminationTest extends EarlyReadEliminationTest { @Test public void testUnsafe3() { - StructuredGraph graph = processMethod("testUnsafe3Snippet", false); + StructuredGraph graph = processMethod("testUnsafe3Snippet"); assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count()); } @@ -172,28 +173,11 @@ public class PEAReadEliminationTest extends EarlyReadEliminationTest { @Test public void testUnsafe4() { - StructuredGraph graph = processMethod("testUnsafe4Snippet", false); + StructuredGraph graph = processMethod("testUnsafe4Snippet"); assertDeepEquals(3, graph.getNodes().filter(RawLoadNode.class).count()); } - private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1; - private static final long offsetLong2 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 2; - - public static int testUnsafe5Snippet(int v, long[] array) { - int s = UNSAFE.getInt(array, offsetLong1); - UNSAFE.putInt(array, offsetLong1, v); - UNSAFE.putInt(array, offsetLong2, v); - return s + UNSAFE.getInt(array, offsetLong1) + UNSAFE.getInt(array, offsetLong2); - } - - @Test - public void testUnsafe5() { - StructuredGraph graph = processMethod("testUnsafe5Snippet", false); - assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count()); - } - - @Override - protected StructuredGraph processMethod(final String snippet, boolean doLowering) { + protected StructuredGraph processMethod(final String snippet) { StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); HighTierContext context = getDefaultHighTierContext(); new InliningPhase(new CanonicalizerPhase()).apply(graph, context); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/TrufflePEATest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/TrufflePEATest.java new file mode 100644 index 00000000000..81ee0d6eccc --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/TrufflePEATest.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.compiler.core.test.ea; + +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.extended.RawLoadNode; +import org.graalvm.compiler.nodes.extended.RawStoreNode; +import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; +import org.junit.Test; +import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +public class TrufflePEATest extends GraalCompilerTest { + + /** + * This class mimics the behavior of {@code FrameWithoutBoxing}. + */ + static class Frame { + long[] primitiveLocals; + + Frame(int size) { + primitiveLocals = new long[size]; + } + } + + /** + * This class mimics the behavior of {@code DynamicObjectL6I6}. + */ + static class DynamicObject { + int primitiveField0; + int primitiveField1; + } + + private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1; + private static final long offsetLong2 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 2; + + private static final long primitiveField0Offset; + + static { + try { + Field primitiveField0 = DynamicObject.class.getDeclaredField("primitiveField0"); + primitiveField0Offset = UNSAFE.objectFieldOffset(primitiveField0); + } catch (NoSuchFieldException | SecurityException e) { + throw new AssertionError(e); + } + } + + public static int unsafeAccessToLongArray(int v, Frame frame) { + long[] array = frame.primitiveLocals; + int s = UNSAFE.getInt(array, offsetLong1); + UNSAFE.putInt(array, offsetLong1, v); + UNSAFE.putInt(array, offsetLong2, v); + return s + UNSAFE.getInt(array, offsetLong1) + UNSAFE.getInt(array, offsetLong2); + } + + @Test + public void testUnsafeAccessToLongArray() { + StructuredGraph graph = processMethod("unsafeAccessToLongArray"); + assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count()); + } + + /** + * The following value should be less than the default value of + * {@link GraalOptions#MaximumEscapeAnalysisArrayLength}. + */ + private static final int FRAME_SIZE = 16; + + public static long newFrame(long v) { + Frame frame = new Frame(FRAME_SIZE); + // Testing unsafe accesses with other kinds requires special handling of the initialized + // entry kind. + UNSAFE.putLong(frame.primitiveLocals, offsetLong1, v); + return UNSAFE.getLong(frame.primitiveLocals, offsetLong1); + } + + @Test + public void testNewFrame() { + StructuredGraph graph = processMethod("newFrame"); + assertDeepEquals(0, graph.getNodes().filter(CommitAllocationNode.class).count()); + assertDeepEquals(0, graph.getNodes().filter(RawLoadNode.class).count()); + assertDeepEquals(0, graph.getNodes().filter(RawStoreNode.class).count()); + } + + protected StructuredGraph processMethod(final String snippet) { + StructuredGraph graph = parseEager(snippet, StructuredGraph.AllowAssumptions.NO); + HighTierContext context = getDefaultHighTierContext(); + new InliningPhase(new CanonicalizerPhase()).apply(graph, context); + new PartialEscapePhase(true, true, new CanonicalizerPhase(), null, graph.getOptions()).apply(graph, context); + return graph; + } + + public static double accessDynamicObject(double v) { + DynamicObject obj = new DynamicObject(); + UNSAFE.putDouble(obj, primitiveField0Offset, v); + return UNSAFE.getDouble(obj, primitiveField0Offset); + } + + @Test + public void testAccessDynamicObject() { + StructuredGraph graph = processMethod("accessDynamicObject"); + assertDeepEquals(0, graph.getNodes().filter(CommitAllocationNode.class).count()); + assertDeepEquals(0, graph.getNodes().filter(RawLoadNode.class).count()); + assertDeepEquals(0, graph.getNodes().filter(RawStoreNode.class).count()); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java index 1b7f0d1327c..d557f5dad63 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java @@ -256,7 +256,7 @@ public class StaticAnalysis { * yet and the bytecode parser would only create a graph. */ Plugins plugins = new Plugins(new InvocationPlugins()); - GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); /* * For simplicity, we ignore all exception handling during the static analysis. * This is a constraint of this example code, a real static analysis needs to diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java index cc0737e2180..b3297da7789 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java @@ -181,6 +181,12 @@ public class GraalError extends Error { public String toString() { StringBuilder str = new StringBuilder(); str.append(super.toString()); + str.append(context()); + return str.toString(); + } + + public String context() { + StringBuilder str = new StringBuilder(); for (String s : context) { str.append("\n\tat ").append(s); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java index 7c886d37cb0..fa468561191 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java @@ -38,6 +38,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.function.Predicate; +import java.util.function.Supplier; import org.graalvm.compiler.core.common.Fields; import org.graalvm.compiler.core.common.type.AbstractPointerStamp; @@ -598,6 +599,15 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface { } } + /** + * Update the source position only if it is null. + */ + public void updateNodeSourcePosition(Supplier sourcePositionSupp) { + if (this.sourcePosition == null) { + setNodeSourcePosition(sourcePositionSupp.get()); + } + } + public DebugCloseable withNodeSourcePosition() { return graph.withNodeSourcePosition(this); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java index 31148d71e19..461d162f9e5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java @@ -195,7 +195,7 @@ public final class NodeBitMap extends NodeIdAccessor implements NodeIterable clear the bit and continue searching - bits[wordIndex] = bits[wordIndex] & ~(1 << bitIndex); + bits[wordIndex] = bits[wordIndex] & ~(1L << bitIndex); int nextNodeId = nodeId + 1; if ((nextNodeId & (Long.SIZE - 1)) == 0) { // we reached the end of this word diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java index 0fb58738803..22844e93006 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java @@ -28,6 +28,10 @@ import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SY import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL; import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS; import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL; +import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE; +import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE; +import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE; +import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS; import java.util.ArrayList; import java.util.List; @@ -39,6 +43,7 @@ import org.graalvm.compiler.core.amd64.AMD64LIRKindTool; import org.graalvm.compiler.core.amd64.AMD64MoveFactoryBase.BackupSlotProvider; import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; import org.graalvm.compiler.core.common.spi.LIRKindTool; import org.graalvm.compiler.debug.DebugContext; @@ -415,49 +420,49 @@ public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSp return result; } - @Override - public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_STRING_BY_SYMBOL); - Constant[] constants = new Constant[]{constant}; - AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)}; - Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE}; + private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, Object[] notes, Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(foreignCall); append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); return emitMove(result); } + private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, AllocatableValue[] constantDescriptions, LIRFrameState frameState) { + Constant[] constants = new Constant[]{constant}; + Object[] notes = new Object[]{action}; + return emitConstantRetrieval(foreignCall, notes, constants, constantDescriptions, frameState); + } + + private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, Value constantDescription, LIRFrameState frameState) { + AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)}; + return emitConstantRetrieval(foreignCall, action, constant, constantDescriptions, frameState); + } + + @Override + public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { + return emitConstantRetrieval(RESOLVE_STRING_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState); + } + @Override public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_KLASS_BY_SYMBOL); - Constant[] constants = new Constant[]{constant}; - AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)}; - Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE}; - append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); - AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); - return emitMove(result); - } - - @Override - public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) { - ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS); - Constant[] constants = new Constant[]{method}; - AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)}; - Object[] notes = new Object[]{HotSpotConstantLoadAction.LOAD_COUNTERS}; - append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); - AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); - return emitMove(result); - + return emitConstantRetrieval(RESOLVE_KLASS_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState); } @Override public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(INITIALIZE_KLASS_BY_SYMBOL); - Constant[] constants = new Constant[]{constant}; - AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)}; - Object[] notes = new Object[]{HotSpotConstantLoadAction.INITIALIZE}; - append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); - AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); - return emitMove(result); + return emitConstantRetrieval(INITIALIZE_KLASS_BY_SYMBOL, INITIALIZE, constant, constantDescription, frameState); + } + + @Override + public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) { + AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)}; + return emitConstantRetrieval(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, LOAD_COUNTERS, method, constantDescriptions, frameState); + } + + @Override + public Value emitResolveDynamicInvoke(Constant appendix, LIRFrameState frameState) { + AllocatableValue[] constantDescriptions = new AllocatableValue[0]; + return emitConstantRetrieval(RESOLVE_DYNAMIC_INVOKE, INITIALIZE, appendix, constantDescriptions, frameState); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java index 29a70ce9d17..883a91dd2fe 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java @@ -27,6 +27,7 @@ import static jdk.vm.ci.sparc.SPARCKind.XWORD; import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; +import org.graalvm.compiler.asm.sparc.SPARCAssembler; import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.calc.Condition; @@ -255,7 +256,7 @@ public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSp @Override public void emitPrefetchAllocate(Value address) { SPARCAddressValue addr = asAddressValue(address); - append(new SPARCPrefetchOp(addr, config.allocatePrefetchInstr)); + append(new SPARCPrefetchOp(addr, SPARCAssembler.Fcn.SeveralWritesAndPossiblyReads)); } public StackSlot getDeoptimizationRescueSlot() { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java index abd9455ec13..0c7cbe5fa49 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java @@ -52,8 +52,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.ServiceLoader; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -475,6 +477,7 @@ public final class CompileTheWorld { private void compile(String classPath) throws IOException { final String[] entries = classPath.split(File.pathSeparator); long start = System.currentTimeMillis(); + Map initialThreads = Thread.getAllStackTraces(); try { // compile dummy method to get compiler initialized outside of the @@ -549,7 +552,13 @@ public final class CompileTheWorld { classFileCounter++; - if (className.startsWith("jdk.management.") || className.startsWith("jdk.internal.cmm.*")) { + if (className.startsWith("jdk.management.") || + className.startsWith("jdk.internal.cmm.*") || + // GR-5881: The class initializer for + // sun.tools.jconsole.OutputViewer + // spawns non-daemon threads for redirecting sysout and syserr. + // These threads tend to cause deadlock at VM exit + className.startsWith("sun.tools.jconsole.")) { continue; } @@ -643,6 +652,33 @@ public final class CompileTheWorld { } else { TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), compileTime.get(), memoryUsed.get()); } + + // Apart from the main thread, there should be only be daemon threads + // alive now. If not, then a class initializer has probably started + // a thread that could cause a deadlock while trying to exit the VM. + // One known example of this is sun.tools.jconsole.OutputViewer which + // spawns threads to redirect sysout and syserr. To help debug such + // scenarios, the stacks of potentially problematic threads are dumped. + Map suspiciousThreads = new HashMap<>(); + for (Map.Entry e : Thread.getAllStackTraces().entrySet()) { + Thread thread = e.getKey(); + if (thread != Thread.currentThread() && !initialThreads.containsKey(thread) && !thread.isDaemon() && thread.isAlive()) { + suspiciousThreads.put(thread, e.getValue()); + } + } + if (!suspiciousThreads.isEmpty()) { + TTY.println("--- Non-daemon threads started during CTW ---"); + for (Map.Entry e : suspiciousThreads.entrySet()) { + Thread thread = e.getKey(); + if (thread.isAlive()) { + TTY.println(thread.toString() + " " + thread.getState()); + for (StackTraceElement ste : e.getValue()) { + TTY.println("\tat " + ste); + } + } + } + TTY.println("---------------------------------------------"); + } } private synchronized void startThreads() { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest.java new file mode 100644 index 00000000000..29c27bfa75d --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.test; + +import java.util.function.IntPredicate; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import java.security.PrivilegedAction; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.hotspot.meta.HotSpotClassInitializationPlugin; +import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase; +import org.graalvm.compiler.phases.common.GuardLoweringPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; +import org.graalvm.compiler.phases.tiers.MidTierContext; +import org.junit.Assert; +import org.junit.Test; + +public class HotSpotInvokeDynamicPluginTest extends HotSpotGraalCompilerTest { + @Override + protected Plugins getDefaultGraphBuilderPlugins() { + Plugins plugins = super.getDefaultGraphBuilderPlugins(); + plugins.setClassInitializationPlugin(new HotSpotClassInitializationPlugin()); + plugins.setInvokeDynamicPlugin(new HotSpotInvokeDynamicPlugin() { + @Override + public boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int index, int opcode) { + // Allow invokedynamic testing with older JVMCI + ResolvedJavaMethod m = builder.getMethod(); + if (m.getName().startsWith("invokeDynamic") && m.getDeclaringClass().getName().equals("Lorg/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest;")) { + return false; + } + return super.isResolvedDynamicInvoke(builder, index, opcode); + } + + @Override + public boolean supportsDynamicInvoke(GraphBuilderContext builder, int index, int opcode) { + // Allow invokehandle testing with older JVMCI + ResolvedJavaMethod m = builder.getMethod(); + if (m.getName().startsWith("invokeHandle") && m.getDeclaringClass().getName().equals("Lorg/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest;")) { + return true; + } + return super.supportsDynamicInvoke(builder, index, opcode); + } + }); + return plugins; + } + + @Override + protected InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + return InlineInfo.DO_NOT_INLINE_NO_EXCEPTION; + } + + private void test(String name, int expectedResolves, int expectedStubCalls) { + StructuredGraph graph = parseEager(name, AllowAssumptions.NO, new OptionValues(getInitialOptions(), GraalOptions.GeneratePIC, true)); + MidTierContext midTierContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo()); + + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + Assert.assertEquals(expectedResolves, graph.getNodes().filter(ResolveDynamicConstantNode.class).count()); + Assert.assertEquals(0, graph.getNodes().filter(ResolveDynamicStubCall.class).count()); + PhaseContext context = new PhaseContext(getProviders()); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + new GuardLoweringPhase().apply(graph, midTierContext); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context); + new FrameStateAssignmentPhase().apply(graph); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, context); + Assert.assertEquals(0, graph.getNodes().filter(ResolveDynamicConstantNode.class).count()); + Assert.assertEquals(expectedStubCalls, graph.getNodes().filter(ResolveDynamicStubCall.class).count()); + } + + public static IntPredicate invokeDynamic1() { + IntPredicate i = (v) -> v > 1; + return i; + } + + public static PrivilegedAction invokeDynamic2(String s) { + return s::length; + } + + static final MethodHandle objToStringMH; + + static { + MethodHandle mh = null; + try { + mh = MethodHandles.lookup().findVirtual(Object.class, "toString", MethodType.methodType(String.class)); + } catch (Exception e) { + } + objToStringMH = mh; + } + + // invokehandle + public static String invokeHandle1(Object o) throws Throwable { + return (String) objToStringMH.invokeExact(o); + } + + @Test + public void test1() { + test("invokeDynamic1", 1, 1); + } + + @Test + public void test2() { + test("invokeDynamic2", 1, 1); + } + + @Test + public void test3() { + test("invokeHandle1", 1, 1); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HsErrLogTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HsErrLogTest.java new file mode 100644 index 00000000000..a6c762142e2 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HsErrLogTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.test; + +import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine; +import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.test.SubprocessUtil; +import org.graalvm.compiler.test.SubprocessUtil.Subprocess; +import org.junit.Assert; +import org.junit.Test; + +import sun.misc.Unsafe; + +/** + * Tests that a hs_err crash log contains expected content. + */ +public class HsErrLogTest extends GraalCompilerTest { + + @Test + public void test1() throws IOException, InterruptedException { + List args = new ArrayList<>(); + if (Java8OrEarlier) { + args.add("-XX:-UseJVMCIClassLoader"); + } + args.add("-XX:+UseJVMCICompiler"); + args.add("-XX:CompileOnly=" + Crasher.class.getName() + "::tryCrash"); + args.add(Crasher.class.getName()); + testHelper(args); + } + + private static final boolean VERBOSE = Boolean.getBoolean(HsErrLogTest.class.getSimpleName() + ".verbose"); + + private static void testHelper(List extraVmArgs, String... mainClassAndArgs) throws IOException, InterruptedException { + List vmArgs = withoutDebuggerArguments(getVMCommandLine()); + vmArgs.removeIf(a -> a.startsWith("-Dgraal.")); + vmArgs.remove("-esa"); + vmArgs.remove("-ea"); + vmArgs.addAll(extraVmArgs); + + Subprocess proc = SubprocessUtil.java(vmArgs, mainClassAndArgs); + if (VERBOSE) { + System.out.println(proc); + } + + Pattern re = Pattern.compile("# +(.*hs_err_pid[\\d]+\\.log)"); + + for (String line : proc.output) { + Matcher m = re.matcher(line); + if (m.matches()) { + File path = new File(m.group(1)); + Assert.assertTrue(path.toString(), path.exists()); + checkHsErr(path); + return; + } + } + + Assert.fail("Could not find " + re.pattern()); + } + + private static void checkHsErr(File hsErrPath) { + try (BufferedReader br = new BufferedReader(new FileReader(hsErrPath))) { + String line = br.readLine(); + String sig = Crasher.class.getName() + ".tryCrash(JI)I"; + List lines = new ArrayList<>(); + while (line != null) { + if (line.contains(sig)) { + if (!VERBOSE) { + hsErrPath.delete(); + } + return; + } + lines.add(line); + line = br.readLine(); + } + throw new AssertionError("Could not find line containing \"" + sig + "\" in " + hsErrPath + + ":" + System.lineSeparator() + String.join(System.lineSeparator(), lines)); + } catch (IOException e) { + throw new AssertionError(e); + } + } +} + +class Crasher { + public static void main(String[] args) { + int iter = 0; + long mem = UNSAFE.allocateMemory(1000); + while (iter < Integer.MAX_VALUE) { + tryCrash(mem, iter); + iter++; + } + } + + protected static int tryCrash(long mem, int iter) { + if (GraalDirectives.inCompiledCode()) { + UNSAFE.putInt(0, iter); + return 0; + } else { + UNSAFE.putInt(mem, iter); + return UNSAFE.getInt(mem); + } + } + + static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + // Fast path when we are trusted. + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + // Slow path when we are not trusted. + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java index 42377130b1c..57d5721bf5f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java @@ -240,7 +240,7 @@ public class CompilationTask { } /** - * @return the compilation id plus a trailing '%' is the compilation is an OSR to match + * @return the compilation id plus a trailing '%' if the compilation is an OSR to match * PrintCompilation style output */ public String getIdString() { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java index 2e1e3a62fe0..bfe32422746 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java @@ -29,7 +29,6 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; -import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; @@ -73,7 +72,6 @@ public abstract class CompilerConfigurationFactory implements Comparable factories = Assertions.assertionsEnabled() ? new ArrayList<>() : null; - - private static boolean checkAndAddNewFactory(CompilerConfigurationFactory factory) { + private static boolean checkUnique(CompilerConfigurationFactory factory, List factories) { for (CompilerConfigurationFactory other : factories) { - assert !other.name.equals(factory.name) : factory.getClass().getName() + " cannot have the same selector as " + other.getClass().getName() + ": " + factory.name; - assert other.autoSelectionPriority != factory.autoSelectionPriority : factory.getClass().getName() + " cannot have the same auto-selection priority as " + other.getClass().getName() + - ": " + factory.autoSelectionPriority; + if (other != factory) { + assert !other.name.equals(factory.name) : factory.getClass().getName() + " cannot have the same selector as " + other.getClass().getName() + ": " + factory.name; + assert other.autoSelectionPriority != factory.autoSelectionPriority : factory.getClass().getName() + " cannot have the same auto-selection priority as " + + other.getClass().getName() + + ": " + factory.autoSelectionPriority; + } } - factories.add(factory); return true; } @@ -148,6 +146,7 @@ public abstract class CompilerConfigurationFactory implements Comparable getAllCandidates() { List candidates = new ArrayList<>(); for (CompilerConfigurationFactory candidate : GraalServices.load(CompilerConfigurationFactory.class)) { + assert checkUnique(candidate, candidates); candidates.add(candidate); } Collections.sort(candidates); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java index 9b8b62b462d..4db2271fbd8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -35,6 +35,7 @@ public class CompilerRuntimeHotSpotVMConfig extends HotSpotVMConfigAccess { } public final long resolveStringBySymbol = getAddress("CompilerRuntime::resolve_string_by_symbol"); + public final long resolveDynamicInvoke = getAddress("CompilerRuntime::resolve_dynamic_invoke"); public final long resolveKlassBySymbol = getAddress("CompilerRuntime::resolve_klass_by_symbol"); public final long resolveMethodBySymbolAndLoadCounters = getAddress("CompilerRuntime::resolve_method_by_symbol_and_load_counters"); public final long initializeKlassBySymbol = getAddress("CompilerRuntime::initialize_klass_by_symbol"); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java index f39ecd0dd7c..f314bbd584f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -280,14 +280,14 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { } if (offset == -1) { try { - offset = getFieldOffset(name, Integer.class, "jobject"); + offset = getFieldOffset(name, Integer.class, "OopHandle"); isHandle = true; } catch (JVMCIError e) { } } if (offset == -1) { - throw new JVMCIError("cannot get offset of field " + name + " with type oop or jobject"); + throw new JVMCIError("cannot get offset of field " + name + " with type oop or OopHandle"); } classMirrorOffset = offset; classMirrorIsHandle = isHandle; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java index e0b2f51e231..3a6d2ec302b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -294,6 +294,11 @@ public abstract class HotSpotBackend extends Backend implements FrameMap.Referen */ public static final ForeignCallDescriptor RESOLVE_STRING_BY_SYMBOL = new ForeignCallDescriptor("resolve_string_by_symbol", Object.class, Word.class, Word.class); + /** + * @see ResolveConstantStubCall + */ + public static final ForeignCallDescriptor RESOLVE_DYNAMIC_INVOKE = new ForeignCallDescriptor("resolve_dynamic_invoke", Object.class, Word.class); + /** * @see ResolveConstantStubCall */ diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java index 489bbd73f5f..c77d3eebf18 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java @@ -282,6 +282,13 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler { return suite; } + public Object mbean() { + if (graalRuntime instanceof HotSpotGraalRuntime) { + return ((HotSpotGraalRuntime)graalRuntime).mbean(); + } + return null; + } + /** * Converts {@code method} to a String with {@link JavaMethod#format(String)} and the format * string {@code "%H.%n(%p)"}. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java index 3e433b13378..c56d8105219 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java @@ -316,4 +316,8 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { public Map getCompilationProblemsPerAction() { return compilationProblemsPerAction; } + + final Object mbean() { + return mBean; + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java index 199d51f58c7..770e19bacf2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -68,7 +68,7 @@ public interface HotSpotLIRGenerator extends LIRGeneratorTool { * @return value of loaded address in register */ default Value emitLoadObjectAddress(Constant constant) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to load an object address is not currently supported on %s", target().arch); } /** @@ -79,7 +79,7 @@ public interface HotSpotLIRGenerator extends LIRGeneratorTool { * @return Value of loaded address in register */ default Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to load a metaspace address is not currently supported on %s", target().arch); } /** @@ -90,7 +90,7 @@ public interface HotSpotLIRGenerator extends LIRGeneratorTool { * @return value of loaded global in register */ default Value emitLoadConfigValue(int markId, LIRKind kind) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to load a config value is not currently supported on %s", target().arch); } /** @@ -100,10 +100,21 @@ public interface HotSpotLIRGenerator extends LIRGeneratorTool { * @param constantDescription a description of the string that need to be materialized (and * interned) as java.lang.String, generated with {@link EncodedSymbolConstant} * @param frameState frame state for the runtime call - * @return Returns the address of the requested constant. + * @return the address of the requested constant. */ default Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to resolve an object constant is not currently supported on %s", target().arch); + } + + /** + * Emits code to resolve a dynamic constant. + * + * @param constant original constant + * @param frameState frame state for the runtime call + * @return the address of the requested constant. + */ + default Value emitResolveDynamicInvoke(Constant constant, LIRFrameState frameState) { + throw new GraalError("Emitting code to resolve a dynamic constant is not currently supported on %s", target().arch); } /** @@ -113,10 +124,10 @@ public interface HotSpotLIRGenerator extends LIRGeneratorTool { * @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant} * generated by {@link EncodedSymbolConstant} * @param frameState frame state for the runtime call - * @return Returns the address of the requested constant. + * @return the address of the requested constant. */ default Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to resolve a metaspace constant is not currently supported on %s", target().arch); } /** @@ -129,10 +140,10 @@ public interface HotSpotLIRGenerator extends LIRGeneratorTool { * @param methodDescription is symbolic description of the constant generated by * {@link EncodedSymbolConstant} * @param frameState frame state for the runtime call - * @return Returns the address of the requested constant. + * @return the address of the requested constant. */ default Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to resolve a method and load counters is not currently supported on %s", target().arch); } /** @@ -144,10 +155,10 @@ public interface HotSpotLIRGenerator extends LIRGeneratorTool { * @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant} * generated by {@link EncodedSymbolConstant} * @param frameState frame state for the runtime call - * @return Returns the address of the requested constant. + * @return the address of the requested constant. */ default Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to initialize a class is not currently supported on %s", target().arch); } /** @@ -156,7 +167,7 @@ public interface HotSpotLIRGenerator extends LIRGeneratorTool { * @return value of the counter */ default Value emitRandomSeed() { - throw GraalError.unimplemented(); + throw new GraalError("Emitting code to return a random seed is not currently supported on %s", target().arch); } /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java index 97a5c5b6e7d..268dce0937a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -24,7 +24,6 @@ package org.graalvm.compiler.hotspot.meta; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; import static org.graalvm.compiler.core.common.GraalOptions.AlwaysInlineVTableStubs; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.InlineVTableStubs; import static org.graalvm.compiler.core.common.GraalOptions.OmitHotExceptionStacktrace; import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END; @@ -70,6 +69,7 @@ import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier; import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier; import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; import org.graalvm.compiler.hotspot.nodes.type.HotSpotNarrowOopStamp; @@ -214,10 +214,8 @@ public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider arraycopySnippets = new ArrayCopySnippets.Templates(options, factories, runtime, providers, target); stringToBytesSnippets = new StringToBytesSnippets.Templates(options, factories, providers, target); hashCodeSnippets = new HashCodeSnippets.Templates(options, factories, providers, target); - if (GeneratePIC.getValue(options)) { - resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target); - profileSnippets = new ProfileSnippets.Templates(options, factories, providers, target); - } + resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target); + profileSnippets = new ProfileSnippets.Templates(options, factories, providers, target); providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(options, factories, providers, target)); } @@ -364,6 +362,10 @@ public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider } } else if (n instanceof IdentityHashCodeNode) { hashCodeSnippets.lower((IdentityHashCodeNode) n, tool); + } else if (n instanceof ResolveDynamicConstantNode) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { + resolveConstantSnippets.lower((ResolveDynamicConstantNode) n, tool); + } } else if (n instanceof ResolveConstantNode) { if (graph.getGuardsStage().areFrameStatesAtDeopts()) { resolveConstantSnippets.lower((ResolveConstantNode) n, tool); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index ef40c436ade..61fbadca3b6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -22,8 +22,6 @@ */ package org.graalvm.compiler.hotspot.meta; -import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateRecompile; -import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved; import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION; @@ -63,7 +61,6 @@ import org.graalvm.compiler.hotspot.replacements.ThreadSubstitutions; import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyNode; import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.DeoptimizeNode; import org.graalvm.compiler.nodes.DynamicPiNode; import org.graalvm.compiler.nodes.FixedGuardNode; import org.graalvm.compiler.nodes.LogicNode; @@ -80,7 +77,6 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory; -import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode; import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; import org.graalvm.compiler.nodes.memory.address.AddressNode; @@ -101,13 +97,9 @@ import org.graalvm.compiler.word.WordTypes; import org.graalvm.word.LocationIdentity; import jdk.vm.ci.code.CodeUtil; -import jdk.vm.ci.hotspot.HotSpotObjectConstant; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; -import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -139,42 +131,9 @@ public class HotSpotGraphBuilderPlugins { plugins.appendTypePlugin(nodePlugin); plugins.appendNodePlugin(nodePlugin); OptionValues options = replacements.getOptions(); - if (GeneratePIC.getValue(options)) { - // AOT needs to filter out bad invokes - plugins.prependNodePlugin(new NodePlugin() { - @Override - public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { - if (b.parsingIntrinsic()) { - return false; - } - // check if the holder has a valid fingerprint - if (((HotSpotResolvedObjectType) method.getDeclaringClass()).getFingerprint() == 0) { - // Deopt otherwise - b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); - return true; - } - // the last argument that may come from appendix, check if it is a supported - // constant type - if (args.length > 0) { - JavaConstant constant = args[args.length - 1].asJavaConstant(); - if (constant != null && constant instanceof HotSpotObjectConstant) { - HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) ((HotSpotObjectConstant) constant).getType(); - Class clazz = type.mirror(); - if (clazz.equals(String.class)) { - return false; - } - if (Class.class.isAssignableFrom(clazz) && ((HotSpotResolvedObjectType) type).getFingerprint() != 0) { - return false; - } - b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); - return true; - } - } - return false; - } - }); + if (!GeneratePIC.getValue(options)) { + plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true)); } - plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true)); plugins.appendInlineInvokePlugin(replacements); if (InlineDuringParsing.getValue(options)) { plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin()); @@ -196,7 +155,9 @@ public class HotSpotGraphBuilderPlugins { registerClassPlugins(plugins, config, replacementBytecodeProvider); registerSystemPlugins(invocationPlugins, foreignCalls); registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacementBytecodeProvider); - registerCallSitePlugins(invocationPlugins); + if (!GeneratePIC.getValue(options)) { + registerCallSitePlugins(invocationPlugins); + } registerReflectionPlugins(invocationPlugins, replacementBytecodeProvider); registerConstantPoolPlugins(invocationPlugins, wordTypes, config, replacementBytecodeProvider); registerAESPlugins(invocationPlugins, config, replacementBytecodeProvider); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java index c6238a4a2fd..36618783bfc 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, 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 @@ -44,6 +44,7 @@ import static org.graalvm.compiler.hotspot.HotSpotBackend.MUL_ADD; import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_ARRAY; import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_INSTANCE; import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY; +import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE; import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL; import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS; import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL; @@ -305,6 +306,7 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall registerForeignCall(WRONG_METHOD_HANDLER, c.handleWrongMethodStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); CompilerRuntimeHotSpotVMConfig cr = new CompilerRuntimeHotSpotVMConfig(HotSpotJVMCIRuntime.runtime().getConfigStore()); linkForeignCall(options, providers, RESOLVE_STRING_BY_SYMBOL, cr.resolveStringBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION); + linkForeignCall(options, providers, RESOLVE_DYNAMIC_INVOKE, cr.resolveDynamicInvoke, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any()); linkForeignCall(options, providers, RESOLVE_KLASS_BY_SYMBOL, cr.resolveKlassBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any()); linkForeignCall(options, providers, RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, cr.resolveMethodBySymbolAndLoadCounters, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(options, providers, INITIALIZE_KLASS_BY_SYMBOL, cr.initializeKlassBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any()); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvokeDynamicPlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvokeDynamicPlugin.java new file mode 100644 index 00000000000..ec2c62b3eb4 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvokeDynamicPlugin.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.meta; + +import org.graalvm.compiler.bytecode.Bytecodes; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; + +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.ConstantPool; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class HotSpotInvokeDynamicPlugin implements InvokeDynamicPlugin { + + private static final Class hscp; + private static final MethodHandle isResolvedDynamicInvokeMH; + + static { + MethodHandle m = null; + Class c = null; + try { + c = Class.forName("jdk.vm.ci.hotspot.HotSpotConstantPool").asSubclass(ConstantPool.class); + m = MethodHandles.lookup().findVirtual(c, "isResolvedDynamicInvoke", MethodType.methodType(boolean.class, int.class, int.class)); + } catch (Exception e) { + } + isResolvedDynamicInvokeMH = m; + hscp = c; + } + + private static boolean isResolvedDynamicInvoke(ConstantPool constantPool, int index, int opcode) { + if (isResolvedDynamicInvokeMH != null) { + if (!hscp.isInstance(constantPool)) { + return false; + } + try { + return (boolean) isResolvedDynamicInvokeMH.invoke(constantPool, index, opcode); + } catch (Throwable t) { + throw GraalError.shouldNotReachHere(t); + } + } + throw GraalError.shouldNotReachHere("isResolvedDynamicInvokeMH not set"); + } + + private final DynamicTypeStore dynoStore; + private final boolean treatAppendixAsConstant; + + public HotSpotInvokeDynamicPlugin(DynamicTypeStore dynoStore, boolean treatAppendixAsConstant) { + this.dynoStore = dynoStore; + this.treatAppendixAsConstant = treatAppendixAsConstant; + } + + public HotSpotInvokeDynamicPlugin(DynamicTypeStore dynoStore) { + this(dynoStore, true); + } + + public HotSpotInvokeDynamicPlugin() { + this(null); + } + + // invokehandle support + @Override + public boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int index, int opcode) { + ConstantPool constantPool = builder.getCode().getConstantPool(); + if (isResolvedDynamicInvokeMH == null) { + // If older JVMCI, but HotSpotInvokeDynamicPlugin is being + // used for testing, return true so that we continue along the + // plugin path. + return true; + } + return isResolvedDynamicInvoke(constantPool, index, opcode); + } + + @Override + public boolean supportsDynamicInvoke(GraphBuilderContext builder, int index, int opcode) { + return opcode == Bytecodes.INVOKEDYNAMIC || isResolvedDynamicInvokeMH != null; + } + + public DynamicTypeStore getDynamicTypeStore() { + return dynoStore; + } + + @Override + public void recordDynamicMethod(GraphBuilderContext builder, int index, int opcode, ResolvedJavaMethod target) { + assert supportsDynamicInvoke(builder, index, opcode); + HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) builder.getMethod(); + HotSpotResolvedObjectType methodHolder = method.getDeclaringClass(); + + HotSpotResolvedJavaMethod adapter = (HotSpotResolvedJavaMethod) target; + if (dynoStore != null) { + dynoStore.recordAdapter(opcode, methodHolder, index, adapter); + } + } + + @Override + public ValueNode genAppendixNode(GraphBuilderContext builder, int index, int opcode, JavaConstant appendixConstant, FrameState frameState) { + JavaConstant appendix = appendixConstant; + assert supportsDynamicInvoke(builder, index, opcode); + HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) builder.getMethod(); + HotSpotResolvedObjectType methodHolder = method.getDeclaringClass(); + + if (dynoStore != null) { + appendix = dynoStore.recordAppendix(opcode, methodHolder, index, appendix); + } + + ConstantNode appendixNode = ConstantNode.forConstant(appendix, builder.getMetaAccess(), builder.getGraph()); + + Stamp appendixStamp = appendixNode.stamp(); + Stamp resolveStamp = treatAppendixAsConstant ? appendixStamp : appendixStamp.unrestricted(); + ResolveDynamicConstantNode resolveNode = new ResolveDynamicConstantNode(resolveStamp, appendixNode); + ResolveDynamicConstantNode added = builder.append(resolveNode); + assert added == resolveNode; + added.setStateBefore(frameState); + return resolveNode; + } + + public interface DynamicTypeStore { + + void recordAdapter(int opcode, HotSpotResolvedObjectType holder, int cpi, HotSpotResolvedJavaMethod adapter); + + JavaConstant recordAppendix(int opcode, HotSpotResolvedObjectType holder, int cpi, JavaConstant appendix); + + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java new file mode 100644 index 00000000000..813055bd6d1 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.nodes.aot; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; + +import org.graalvm.word.LocationIdentity; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; + +@NodeInfo(cycles = CYCLES_4, size = SIZE_16) +public class ResolveDynamicConstantNode extends DeoptimizingFixedWithNextNode implements Lowerable, MemoryCheckpoint.Single { + public static final NodeClass TYPE = NodeClass.create(ResolveDynamicConstantNode.class); + + @Input ValueNode value; + + public ResolveDynamicConstantNode(Stamp valueStamp, ValueNode value) { + super(TYPE, valueStamp); + this.value = value; + } + + public ValueNode value() { + return value; + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public LocationIdentity getLocationIdentity() { + return LocationIdentity.any(); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java new file mode 100644 index 00000000000..dd3a558d79e --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.nodes.aot; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; + +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.DeoptimizingNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.word.LocationIdentity; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.Value; + +/** + * A call to the VM via a regular stub. + */ +@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_16) +public class ResolveDynamicStubCall extends AbstractMemoryCheckpoint implements LIRLowerable, Canonicalizable, DeoptimizingNode.DeoptBefore, MemoryCheckpoint.Single { + public static final NodeClass TYPE = NodeClass.create(ResolveDynamicStubCall.class); + + @OptionalInput protected ValueNode value; + @OptionalInput(InputType.State) protected FrameState stateBefore; + protected Constant constant; + + public ResolveDynamicStubCall(ValueNode value) { + super(TYPE, value.stamp()); + this.value = value; + } + + @NodeIntrinsic + public static native Object resolveInvoke(Object value); + + @Override + public Node canonical(CanonicalizerTool tool) { + if (value != null) { + constant = GraphUtil.foldIfConstantAndRemove(this, value); + } + return this; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + assert constant != null : "Expected the value to fold: " + value; + Value result; + LIRFrameState fs = gen.state(this); + assert fs != null : "The stateAfter is null"; + result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitResolveDynamicInvoke(constant, fs); + gen.setResult(this, result); + } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public LocationIdentity getLocationIdentity() { + return LocationIdentity.any(); + } + + @Override + public FrameState stateBefore() { + return stateBefore; + } + + @Override + public void setStateBefore(FrameState f) { + updateUsages(stateBefore, f); + stateBefore = f; + } + + @Override + public void markDeleted() { + throw GraalError.shouldNotReachHere("ResolveDynamicStubCall node deleted"); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java index 186dcabe550..e6972526ff8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java @@ -42,6 +42,7 @@ import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode; import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractMergeNode; @@ -107,6 +108,7 @@ public class ReplaceConstantNodesPhase extends BasePhase { // @formatter:off return n instanceof LoadConstantIndirectlyNode || n instanceof LoadConstantIndirectlyFixedNode || + n instanceof ResolveDynamicConstantNode || n instanceof ResolveConstantNode || n instanceof InitializeKlassNode; // @formatter:on diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java index 7cc363e8e41..47d8985acac 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -36,7 +36,9 @@ import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassStubCall; import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersIndirectlyNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall; import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersStubCall; @@ -72,6 +74,15 @@ public class ResolveConstantSnippets implements Snippets { return result; } + @Snippet + public static Object resolveDynamicConstant(Object constant) { + Object result = LoadConstantIndirectlyNode.loadObject(constant); + if (probability(VERY_SLOW_PATH_PROBABILITY, result == null)) { + result = ResolveDynamicStubCall.resolveInvoke(constant); + } + return result; + } + @Snippet public static KlassPointer resolveKlassConstant(KlassPointer constant) { KlassPointer result = LoadConstantIndirectlyNode.loadKlass(constant); @@ -110,6 +121,7 @@ public class ResolveConstantSnippets implements Snippets { public static class Templates extends AbstractTemplates { private final SnippetInfo resolveObjectConstant = snippet(ResolveConstantSnippets.class, "resolveObjectConstant"); + private final SnippetInfo resolveDynamicConstant = snippet(ResolveConstantSnippets.class, "resolveDynamicConstant"); private final SnippetInfo resolveKlassConstant = snippet(ResolveConstantSnippets.class, "resolveKlassConstant"); private final SnippetInfo resolveMethodAndLoadCounters = snippet(ResolveConstantSnippets.class, "resolveMethodAndLoadCounters"); private final SnippetInfo initializeKlass = snippet(ResolveConstantSnippets.class, "initializeKlass"); @@ -119,6 +131,25 @@ public class ResolveConstantSnippets implements Snippets { super(options, factories, providers, providers.getSnippetReflection(), target); } + public void lower(ResolveDynamicConstantNode resolveConstantNode, LoweringTool tool) { + StructuredGraph graph = resolveConstantNode.graph(); + + ValueNode value = resolveConstantNode.value(); + assert value.isConstant() : "Expected a constant: " + value; + SnippetInfo snippet = resolveDynamicConstant; + + Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("constant", value); + + SnippetTemplate template = template(graph.getDebug(), args); + template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args); + + assert resolveConstantNode.hasNoUsages(); + if (!resolveConstantNode.isDeleted()) { + GraphUtil.killWithUnusedFloatingInputs(resolveConstantNode); + } + } + public void lower(ResolveConstantNode resolveConstantNode, LoweringTool tool) { StructuredGraph graph = resolveConstantNode.graph(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java index 6160540dd56..4c23ddbc6ea 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, 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 @@ -374,6 +374,7 @@ import org.graalvm.compiler.nodes.extended.MembarNode; import org.graalvm.compiler.nodes.extended.StateSplitProxyNode; import org.graalvm.compiler.nodes.extended.ValueAnchorNode; import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; @@ -933,8 +934,13 @@ public class BytecodeParser implements GraphBuilderContext { * @param type the unresolved type of the constant */ protected void handleUnresolvedLoadConstant(JavaType type) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + /* + * Track source position for deopt nodes even if + * GraphBuilderConfiguration.trackNodeSourcePosition is not set. + */ + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -942,7 +948,7 @@ public class BytecodeParser implements GraphBuilderContext { * @param object the object value whose type is being checked against {@code type} */ protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) { - assert !graphBuilderConfig.eagerResolving(); + assert !graphBuilderConfig.unresolvedIsError(); append(new FixedGuardNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), Unresolved, InvalidateRecompile)); frameState.push(JavaKind.Object, appendConstant(JavaConstant.NULL_POINTER)); } @@ -952,9 +958,10 @@ public class BytecodeParser implements GraphBuilderContext { * @param object the object value whose type is being checked against {@code type} */ protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) { - assert !graphBuilderConfig.eagerResolving(); + assert !graphBuilderConfig.unresolvedIsError(); AbstractBeginNode successor = graph.add(new BeginNode()); DeoptimizeNode deopt = graph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), successor, deopt, 1)); lastInstr = successor; frameState.push(JavaKind.Int, appendConstant(JavaConstant.INT_0)); @@ -964,8 +971,9 @@ public class BytecodeParser implements GraphBuilderContext { * @param type the type being instantiated */ protected void handleUnresolvedNewInstance(JavaType type) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -973,8 +981,9 @@ public class BytecodeParser implements GraphBuilderContext { * @param length the length of the array */ protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -982,8 +991,9 @@ public class BytecodeParser implements GraphBuilderContext { * @param dims the dimensions for the multi-array */ protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -991,8 +1001,9 @@ public class BytecodeParser implements GraphBuilderContext { * @param receiver the object containing the field or {@code null} if {@code field} is static */ protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -1001,16 +1012,18 @@ public class BytecodeParser implements GraphBuilderContext { * @param receiver the object containing the field or {@code null} if {@code field} is static */ protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** * @param type */ protected void handleUnresolvedExceptionType(JavaType type) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } /** @@ -1018,8 +1031,9 @@ public class BytecodeParser implements GraphBuilderContext { * @param invokeKind */ protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) { - assert !graphBuilderConfig.eagerResolving(); - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } private AbstractBeginNode handleException(ValueNode exceptionObject, int bci) { @@ -1307,7 +1321,12 @@ public class BytecodeParser implements GraphBuilderContext { return false; } - protected void genInvokeStatic(JavaMethod target) { + protected void genInvokeStatic(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeStatic(target); + } + + void genInvokeStatic(JavaMethod target) { if (callTargetIsResolved(target)) { ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; ResolvedJavaType holder = resolvedTarget.getDeclaringClass(); @@ -1332,6 +1351,11 @@ public class BytecodeParser implements GraphBuilderContext { } } + protected void genInvokeInterface(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeInterface(target); + } + protected void genInvokeInterface(JavaMethod target) { if (callTargetIsResolved(target)) { ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true)); @@ -1341,44 +1365,108 @@ public class BytecodeParser implements GraphBuilderContext { } } - protected void genInvokeDynamic(JavaMethod target) { - if (target instanceof ResolvedJavaMethod) { - JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC); - if (appendix != null) { - frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph)); - } - ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(false)); - appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args); - } else { + protected void genInvokeDynamic(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeDynamic(target); + } + + void genInvokeDynamic(JavaMethod target) { + if (!(target instanceof ResolvedJavaMethod) || !genDynamicInvokeHelper((ResolvedJavaMethod) target, stream.readCPI4(), INVOKEDYNAMIC)) { handleUnresolvedInvoke(target, InvokeKind.Static); } } - protected void genInvokeVirtual(JavaMethod target) { - if (callTargetIsResolved(target)) { - /* - * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...) - * or MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see - * https://wikis.oracle.com/display/HotSpotInternals/Method+handles +and+invokedynamic - */ - boolean hasReceiver = !((ResolvedJavaMethod) target).isStatic(); - JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI(), Bytecodes.INVOKEVIRTUAL); - if (appendix != null) { - frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph)); - } - ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver)); - if (hasReceiver) { - appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); - } else { - appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args); - } - } else { - handleUnresolvedInvoke(target, InvokeKind.Virtual); - } - + protected void genInvokeVirtual(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeVirtual(target); } - protected void genInvokeSpecial(JavaMethod target) { + private boolean genDynamicInvokeHelper(ResolvedJavaMethod target, int cpi, int opcode) { + assert opcode == INVOKEDYNAMIC || opcode == INVOKEVIRTUAL; + + InvokeDynamicPlugin invokeDynamicPlugin = graphBuilderConfig.getPlugins().getInvokeDynamicPlugin(); + + if (opcode == INVOKEVIRTUAL && invokeDynamicPlugin != null && !invokeDynamicPlugin.isResolvedDynamicInvoke(this, cpi, opcode)) { + // regular invokevirtual, let caller handle it + return false; + } + + if (GeneratePIC.getValue(options) && (invokeDynamicPlugin == null || !invokeDynamicPlugin.supportsDynamicInvoke(this, cpi, opcode))) { + // bail out if static compiler and no dynamic type support + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + return true; + } + + JavaConstant appendix = constantPool.lookupAppendix(cpi, opcode); + ValueNode appendixNode = null; + + if (appendix != null) { + if (invokeDynamicPlugin != null) { + invokeDynamicPlugin.recordDynamicMethod(this, cpi, opcode, target); + + // Will perform runtime type checks and static initialization + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + appendixNode = invokeDynamicPlugin.genAppendixNode(this, cpi, opcode, appendix, stateBefore); + } else { + appendixNode = ConstantNode.forConstant(appendix, metaAccess, graph); + } + + frameState.push(JavaKind.Object, appendixNode); + + } else if (GeneratePIC.getValue(options)) { + // Need to emit runtime guard and perform static initialization. + // Not implemented yet. + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + return true; + } + + boolean hasReceiver = (opcode == INVOKEDYNAMIC) ? false : !target.isStatic(); + ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver)); + if (hasReceiver) { + appendInvoke(InvokeKind.Virtual, target, args); + } else { + appendInvoke(InvokeKind.Static, target, args); + } + + return true; + } + + void genInvokeVirtual(JavaMethod target) { + if (!genInvokeVirtualHelper(target)) { + handleUnresolvedInvoke(target, InvokeKind.Virtual); + } + } + + private boolean genInvokeVirtualHelper(JavaMethod target) { + if (!callTargetIsResolved(target)) { + return false; + } + + ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; + int cpi = stream.readCPI(); + + /* + * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...) or + * MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see + * https://wiki.openjdk.java.net/display/HotSpot/Method+handles+and+invokedynamic + */ + + if (genDynamicInvokeHelper(resolvedTarget, cpi, INVOKEVIRTUAL)) { + return true; + } + + ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true)); + appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); + + return true; + } + + protected void genInvokeSpecial(int cpi, int opcode) { + JavaMethod target = lookupMethod(cpi, opcode); + genInvokeSpecial(target); + } + + void genInvokeSpecial(JavaMethod target) { if (callTargetIsResolved(target)) { assert target != null; assert target.getSignature() != null; @@ -2149,9 +2237,9 @@ public class BytecodeParser implements GraphBuilderContext { TTY.println(s); } - protected BytecodeParserError asParserError(Throwable e) { + protected RuntimeException throwParserError(Throwable e) { if (e instanceof BytecodeParserError) { - return (BytecodeParserError) e; + throw (BytecodeParserError) e; } BytecodeParser bp = this; BytecodeParserError res = new BytecodeParserError(e); @@ -2159,7 +2247,7 @@ public class BytecodeParser implements GraphBuilderContext { res.addContext("parsing " + bp.code.asStackTraceElement(bp.bci())); bp = bp.parent; } - return res; + throw res; } protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) { @@ -2837,7 +2925,7 @@ public class BytecodeParser implements GraphBuilderContext { // Don't wrap bailouts as parser errors throw e; } catch (Throwable e) { - throw asParserError(e); + throw throwParserError(e); } if (lastInstr == null || lastInstr.next() != null) { @@ -3257,7 +3345,7 @@ public class BytecodeParser implements GraphBuilderContext { int nextBC = stream.readUByte(nextBCI); if (nextBCI <= currentBlock.endBci && nextBC == Bytecodes.GETFIELD) { stream.next(); - genGetField(lookupField(stream.readCPI(), Bytecodes.GETFIELD), value); + genGetField(stream.readCPI(), Bytecodes.GETFIELD, value); } else { frameState.push(JavaKind.Object, value); } @@ -3506,15 +3594,18 @@ public class BytecodeParser implements GraphBuilderContext { return result; } - private JavaField lookupField(int cpi, int opcode) { + protected JavaField lookupField(int cpi, int opcode) { maybeEagerlyResolve(cpi, opcode); JavaField result = constantPool.lookupField(cpi, method, opcode); + if (graphBuilderConfig.eagerResolving()) { - assert result instanceof ResolvedJavaField : "Not resolved: " + result; - ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass(); - if (!declaringClass.isInitialized()) { - assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass; - declaringClass.initialize(); + assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result; + if (result instanceof ResolvedJavaField) { + ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass(); + if (!declaringClass.isInitialized()) { + assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass; + declaringClass.initialize(); + } } } assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; @@ -3524,11 +3615,11 @@ public class BytecodeParser implements GraphBuilderContext { private Object lookupConstant(int cpi, int opcode) { maybeEagerlyResolve(cpi, opcode); Object result = constantPool.lookupConstant(cpi); - assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result; + assert !graphBuilderConfig.unresolvedIsError() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result; return result; } - private void maybeEagerlyResolve(int cpi, int bytecode) { + protected void maybeEagerlyResolve(int cpi, int bytecode) { if (intrinsicContext != null) { constantPool.loadReferencedType(cpi, bytecode); } else if (graphBuilderConfig.eagerResolving()) { @@ -3653,9 +3744,12 @@ public class BytecodeParser implements GraphBuilderContext { } } - void genNewInstance(int cpi) { + protected void genNewInstance(int cpi) { JavaType type = lookupType(cpi, NEW); + genNewInstance(type); + } + void genNewInstance(JavaType type) { if (!(type instanceof ResolvedJavaType) || !((ResolvedJavaType) type).isInitialized()) { handleUnresolvedNewInstance(type); return; @@ -3790,8 +3884,13 @@ public class BytecodeParser implements GraphBuilderContext { frameState.push(JavaKind.Object, append(createNewMultiArray(resolvedType, dims))); } - private void genGetField(JavaField field) { - genGetField(field, frameState.pop(JavaKind.Object)); + protected void genGetField(int cpi, int opcode) { + genGetField(cpi, opcode, frameState.pop(JavaKind.Object)); + } + + protected void genGetField(int cpi, int opcode, ValueNode receiverInput) { + JavaField field = lookupField(cpi, opcode); + genGetField(field, receiverInput); } private void genGetField(JavaField field, ValueNode receiverInput) { @@ -3867,7 +3966,12 @@ public class BytecodeParser implements GraphBuilderContext { return false; } - private void genPutField(JavaField field) { + protected void genPutField(int cpi, int opcode) { + JavaField field = lookupField(cpi, opcode); + genPutField(field); + } + + protected void genPutField(JavaField field) { genPutField(field, frameState.pop(field.getJavaKind())); } @@ -3895,6 +3999,11 @@ public class BytecodeParser implements GraphBuilderContext { } } + protected void genGetStatic(int cpi, int opcode) { + JavaField field = lookupField(cpi, opcode); + genGetStatic(field); + } + private void genGetStatic(JavaField field) { ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, null); if (resolvedField == null) { @@ -3956,7 +4065,12 @@ public class BytecodeParser implements GraphBuilderContext { return null; } - private void genPutStatic(JavaField field) { + protected void genPutStatic(int cpi, int opcode) { + JavaField field = lookupField(cpi, opcode); + genPutStatic(field); + } + + protected void genPutStatic(JavaField field) { ValueNode value = frameState.pop(field.getJavaKind()); ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, value); if (resolvedField == null) { @@ -4320,15 +4434,15 @@ public class BytecodeParser implements GraphBuilderContext { case DRETURN : genReturn(frameState.pop(JavaKind.Double), JavaKind.Double); break; case ARETURN : genReturn(frameState.pop(JavaKind.Object), JavaKind.Object); break; case RETURN : genReturn(null, JavaKind.Void); break; - case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; - case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; - case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; - case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; - case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; - case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; - case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; - case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; - case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; + case GETSTATIC : cpi = stream.readCPI(); genGetStatic(cpi, opcode); break; + case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(cpi, opcode); break; + case GETFIELD : cpi = stream.readCPI(); genGetField(cpi, opcode); break; + case PUTFIELD : cpi = stream.readCPI(); genPutField(cpi, opcode); break; + case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(cpi, opcode); break; + case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(cpi, opcode); break; + case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(cpi, opcode); break; + case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(cpi, opcode); break; + case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(cpi, opcode); break; case NEW : genNewInstance(stream.readCPI()); break; case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem4.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem4.java new file mode 100644 index 00000000000..a4a98087779 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem4.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.jtt.bytecode; + +import org.junit.Test; + +import org.graalvm.compiler.jtt.JTTTest; + +public class BC_irem4 extends JTTTest { + + public static int test(int a) { + return a % 8; + } + + @Test + public void run0() throws Throwable { + runTest("test", -1); + } + + @Test + public void run1() throws Throwable { + runTest("test", -2); + } + + @Test + public void run2() throws Throwable { + runTest("test", -8); + } + + @Test + public void run3() throws Throwable { + runTest("test", 16); + } + + @Test + public void run4() throws Throwable { + runTest("test", -16); + } + + @Test + public void run5() throws Throwable { + runTest("test", -23); + } + + @Test + public void run6() throws Throwable { + runTest("test", 23); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java index 88040afe52c..157f093c26a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java @@ -34,18 +34,17 @@ public final class SPARCPrefetchOp extends SPARCLIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCPrefetchOp.class); public static final SizeEstimate SIZE = SizeEstimate.create(1); - private final int instr; // AllocatePrefetchInstr + private final SPARCAssembler.Fcn fcn; @Alive({COMPOSITE}) protected SPARCAddressValue address; - public SPARCPrefetchOp(SPARCAddressValue address, int instr) { + public SPARCPrefetchOp(SPARCAddressValue address, SPARCAssembler.Fcn fcn) { super(TYPE, SIZE); this.address = address; - this.instr = instr; + this.fcn = fcn; } @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - assert instr >= 0 && instr < SPARCAssembler.Fcn.values().length : instr; - masm.prefetch(address.toAddress(), SPARCAssembler.Fcn.values()[instr]); + masm.prefetch(address.toAddress(), fcn); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java index 8f87ba89087..1f3f2629e48 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java @@ -466,28 +466,6 @@ public class GraphDecoder { AbstractMergeNode merge = (AbstractMergeNode) node; EndNode singleEnd = merge.forwardEndAt(0); - /* - * In some corner cases, the MergeNode already has PhiNodes. Since there is a single - * EndNode, each PhiNode can only have one input, and we can replace the PhiNode with - * this single input. - */ - for (PhiNode phi : merge.phis()) { - assert phi.inputs().count() == 1 : "input count must match end count"; - Node singlePhiInput = phi.inputs().first(); - - /* - * We do not have the orderID of the PhiNode anymore, so we need to search through - * the complete list of nodes to find a match. - */ - for (int i = 0; i < loopScope.createdNodes.length; i++) { - if (loopScope.createdNodes[i] == phi) { - loopScope.createdNodes[i] = singlePhiInput; - } - } - - phi.replaceAndDelete(singlePhiInput); - } - /* Nodes that would use this merge as the guard need to use the previous block. */ registerNode(loopScope, nodeOrderId, AbstractBeginNode.prevBegin(singleEnd), true, false); @@ -973,8 +951,22 @@ public class GraphDecoder { int phiNodeOrderId = readOrderId(methodScope); ValueNode phiInput = (ValueNode) ensureNodeCreated(methodScope, phiInputScope, phiInputOrderId); - ValueNode existing = (ValueNode) lookupNode(phiNodeScope, phiNodeOrderId); + + if (existing != null && merge.phiPredecessorCount() == 1) { + /* + * When exploding loops and the code after the loop (FULL_EXPLODE_UNTIL_RETURN), + * then an existing value can already be registered: Parsing of the code before the + * loop registers it when preparing for the later merge. The code after the loop, + * which starts with a clone of the values that were created before the loop, sees + * the stale value when processing the merge the first time. We can safely ignore + * the stale value because it will never be needed to be merged (we are exploding + * until we hit a return). + */ + assert methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN && phiNodeScope.loopIteration > 0; + existing = null; + } + if (lazyPhi && (existing == null || existing == phiInput)) { /* Phi function not yet necessary. */ registerNode(phiNodeScope, phiNodeOrderId, phiInput, true, false); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java index f9d2a3d8367..dba8f7295b2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java @@ -30,6 +30,8 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; @@ -52,7 +54,10 @@ import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; import org.graalvm.compiler.nodes.calc.IsNullNode; import org.graalvm.compiler.nodes.calc.NormalizeCompareNode; +import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; +import org.graalvm.compiler.nodes.extended.UnboxNode; import org.graalvm.compiler.nodes.java.InstanceOfNode; +import org.graalvm.compiler.nodes.java.LoadFieldNode; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.util.GraphUtil; @@ -256,6 +261,123 @@ public final class IfNode extends ControlSplitNode implements Simplifiable, LIRL } } } + + if (tryEliminateBoxedReferenceEquals(tool)) { + return; + } + } + + private boolean isUnboxedFrom(MetaAccessProvider meta, ValueNode x, ValueNode src) { + if (x == src) { + return true; + } else if (x instanceof UnboxNode) { + return isUnboxedFrom(meta, ((UnboxNode) x).getValue(), src); + } else if (x instanceof PiNode) { + PiNode pi = (PiNode) x; + return isUnboxedFrom(meta, pi.getOriginalNode(), src); + } else if (x instanceof LoadFieldNode) { + LoadFieldNode load = (LoadFieldNode) x; + ResolvedJavaType integerType = meta.lookupJavaType(Integer.class); + if (load.getValue().stamp().javaType(meta).equals(integerType)) { + return isUnboxedFrom(meta, load.getValue(), src); + } else { + return false; + } + } else { + return false; + } + } + + /** + * Attempts to replace the following pattern: + * + *
    +     * Integer x = ...;
    +     * Integer y = ...;
    +     * if ((x == y) || x.equals(y)) { ... }
    +     * 
    + * + * with: + * + *
    +     * Integer x = ...;
    +     * Integer y = ...;
    +     * if (x.equals(y)) { ... }
    +     * 
    + * + * whenever the probability that the reference check will pass is relatively small. + * + * See GR-1315 for more information. + */ + private boolean tryEliminateBoxedReferenceEquals(SimplifierTool tool) { + if (!(condition instanceof ObjectEqualsNode)) { + return false; + } + + MetaAccessProvider meta = tool.getMetaAccess(); + ObjectEqualsNode equalsCondition = (ObjectEqualsNode) condition; + ValueNode x = equalsCondition.getX(); + ValueNode y = equalsCondition.getY(); + ResolvedJavaType integerType = meta.lookupJavaType(Integer.class); + + // At least one argument for reference equal must be a boxed primitive. + if (!x.stamp().javaType(meta).equals(integerType) && !y.stamp().javaType(meta).equals(integerType)) { + return false; + } + + // The reference equality check is usually more efficient compared to a boxing check. + // The success of the reference equals must therefore be relatively rare, otherwise it makes + // no sense to eliminate it. + if (getTrueSuccessorProbability() > 0.4) { + return false; + } + + // True branch must be empty. + if (trueSuccessor instanceof BeginNode || trueSuccessor instanceof LoopExitNode) { + if (trueSuccessor.next() instanceof EndNode) { + // Empty true branch. + } else { + return false; + } + } else { + return false; + } + + // False branch must only check the unboxed values. + UnboxNode unbox = null; + FixedGuardNode unboxCheck = null; + for (FixedNode node : falseSuccessor.getBlockNodes()) { + if (!(node instanceof BeginNode || node instanceof UnboxNode || node instanceof FixedGuardNode || node instanceof EndNode || + node instanceof LoadFieldNode || node instanceof LoopExitNode)) { + return false; + } + if (node instanceof UnboxNode) { + if (unbox == null) { + unbox = (UnboxNode) node; + } else { + return false; + } + } + if (!(node instanceof FixedGuardNode)) { + continue; + } + FixedGuardNode fixed = (FixedGuardNode) node; + if (!(fixed.condition() instanceof IntegerEqualsNode)) { + continue; + } + IntegerEqualsNode equals = (IntegerEqualsNode) fixed.condition(); + if ((isUnboxedFrom(meta, equals.getX(), x) && isUnboxedFrom(meta, equals.getY(), y)) || (isUnboxedFrom(meta, equals.getX(), y) && isUnboxedFrom(meta, equals.getY(), x))) { + unboxCheck = fixed; + } + } + if (unbox == null || unboxCheck == null) { + return false; + } + + // Falsify the reference check. + setCondition(graph().addOrUnique(LogicConstantNode.contradiction())); + + return true; } /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java index 1c0c1da9e29..6d534e12cdc 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java @@ -60,6 +60,11 @@ public class NamedLocationIdentity extends LocationIdentity implements FormatWit */ public static final LocationIdentity ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("[].length"); + /** + * Denotes an off-heap address. + */ + public static final LocationIdentity OFF_HEAP_LOCATION = NamedLocationIdentity.mutable("OFF_HEAP_LOCATION"); + private final String name; private final boolean immutable; @@ -81,7 +86,7 @@ public class NamedLocationIdentity extends LocationIdentity implements FormatWit /** * Creates a named unique location identity for read operations against immutable memory. - * Immutable memory will never have a visible write in the graph, which is more restictive than + * Immutable memory will never have a visible write in the graph, which is more restrictive than * Java final. * * @param name the name of the new location identity diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java index 05196c51cad..deb5c18d3e5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java @@ -60,12 +60,26 @@ public class SignedRemNode extends IntegerDivRemNode implements LIRLowerable { return this; // this will trap, can not canonicalize } return ConstantNode.forIntegerStamp(stamp(), forX.asJavaConstant().asLong() % y); - } else if (forY.isConstant()) { - long c = forY.asJavaConstant().asLong(); - if (c == 1 || c == -1) { + } else if (forY.isConstant() && forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) { + long constY = forY.asJavaConstant().asLong(); + IntegerStamp xStamp = (IntegerStamp) forX.stamp(); + IntegerStamp yStamp = (IntegerStamp) forY.stamp(); + if (constY < 0 && constY != CodeUtil.minValue(yStamp.getBits())) { + return new SignedRemNode(forX, ConstantNode.forIntegerStamp(yStamp, -constY)).canonical(tool); + } + + if (constY == 1) { return ConstantNode.forIntegerStamp(stamp(), 0); - } else if (c > 0 && CodeUtil.isPowerOf2(c) && forX.stamp() instanceof IntegerStamp && ((IntegerStamp) forX.stamp()).isPositive()) { - return new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), c - 1)); + } else if (CodeUtil.isPowerOf2(constY)) { + if (xStamp.isPositive()) { + return new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), constY - 1)); + } else if (xStamp.isNegative()) { + return new NegateNode(new AndNode(new NegateNode(forX), ConstantNode.forIntegerStamp(stamp(), constY - 1))); + } else { + return new ConditionalNode(IntegerLessThanNode.create(forX, ConstantNode.forIntegerStamp(forX.stamp(), 0)), + new NegateNode(new AndNode(new NegateNode(forX), ConstantNode.forIntegerStamp(stamp(), constY - 1))), + new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), constY - 1))); + } } } return this; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java index 2655035d3a7..63e6dfcffe2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java @@ -30,7 +30,10 @@ import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.ReinterpretNode; import org.graalvm.compiler.nodes.java.LoadFieldNode; @@ -38,19 +41,23 @@ import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.spi.Virtualizable; import org.graalvm.compiler.nodes.spi.VirtualizerTool; +import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; import org.graalvm.word.LocationIdentity; import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaType; /** * Load of a value from a location specified as an offset relative to an object. No null check is * performed before the load. */ @NodeInfo(cycles = CYCLES_2, size = SIZE_1) -public class RawLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable { +public class RawLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable, Canonicalizable { public static final NodeClass TYPE = NodeClass.create(RawLoadNode.class); /** @@ -122,6 +129,32 @@ public class RawLoadNode extends UnsafeAccessNode implements Lowerable, Virtuali } } + @Override + public Node canonical(CanonicalizerTool tool) { + if (!isAnyLocationForced() && getLocationIdentity().isAny()) { + ValueNode targetObject = object(); + if (offset().isConstant() && targetObject.isConstant() && !targetObject.isNullConstant()) { + ConstantNode objectConstant = (ConstantNode) targetObject; + ResolvedJavaType type = StampTool.typeOrNull(objectConstant); + if (type != null && type.isArray()) { + JavaConstant arrayConstant = objectConstant.asJavaConstant(); + if (arrayConstant != null) { + int stableDimension = objectConstant.getStableDimension(); + if (stableDimension > 0) { + long constantOffset = offset().asJavaConstant().asLong(); + Constant constant = stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), arrayConstant, constantOffset); + boolean isDefaultStable = objectConstant.isDefaultStable(); + if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) { + return ConstantNode.forConstant(stamp(), constant, stableDimension - 1, isDefaultStable, tool.getMetaAccess()); + } + } + } + } + } + } + return super.canonical(tool); + } + @Override protected ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field) { return LoadFieldNode.create(assumptions, object(), field); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java index 04839c2ba01..9bd955005ae 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -39,6 +39,7 @@ public class GraphBuilderConfiguration { private InlineInvokePlugin[] inlineInvokePlugins; private LoopExplosionPlugin loopExplosionPlugin; private ClassInitializationPlugin classInitializationPlugin; + private InvokeDynamicPlugin invokeDynamicPlugin; private ProfilingPlugin profilingPlugin; /** @@ -54,6 +55,7 @@ public class GraphBuilderConfiguration { this.inlineInvokePlugins = copyFrom.inlineInvokePlugins; this.loopExplosionPlugin = copyFrom.loopExplosionPlugin; this.classInitializationPlugin = copyFrom.classInitializationPlugin; + this.invokeDynamicPlugin = copyFrom.invokeDynamicPlugin; this.profilingPlugin = copyFrom.profilingPlugin; } @@ -167,6 +169,14 @@ public class GraphBuilderConfiguration { this.classInitializationPlugin = plugin; } + public InvokeDynamicPlugin getInvokeDynamicPlugin() { + return invokeDynamicPlugin; + } + + public void setInvokeDynamicPlugin(InvokeDynamicPlugin plugin) { + this.invokeDynamicPlugin = plugin; + } + public ProfilingPlugin getProfilingPlugin() { return profilingPlugin; } @@ -189,6 +199,7 @@ public class GraphBuilderConfiguration { private static final ResolvedJavaType[] EMPTY = new ResolvedJavaType[]{}; private final boolean eagerResolving; + private final boolean unresolvedIsError; private final BytecodeExceptionMode bytecodeExceptionMode; private final boolean omitAssertions; private final ResolvedJavaType[] skippedExceptionTypes; @@ -216,10 +227,11 @@ public class GraphBuilderConfiguration { Profile } - protected GraphBuilderConfiguration(boolean eagerResolving, BytecodeExceptionMode bytecodeExceptionMode, boolean omitAssertions, boolean insertFullInfopoints, + protected GraphBuilderConfiguration(boolean eagerResolving, boolean unresolvedIsError, BytecodeExceptionMode bytecodeExceptionMode, boolean omitAssertions, boolean insertFullInfopoints, boolean trackNodeSourcePosition, ResolvedJavaType[] skippedExceptionTypes, Plugins plugins) { this.eagerResolving = eagerResolving; + this.unresolvedIsError = unresolvedIsError; this.bytecodeExceptionMode = bytecodeExceptionMode; this.omitAssertions = omitAssertions; this.insertFullInfopoints = insertFullInfopoints; @@ -235,35 +247,52 @@ public class GraphBuilderConfiguration { */ public GraphBuilderConfiguration copy() { Plugins newPlugins = new Plugins(plugins); - GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, - newPlugins); + GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, + skippedExceptionTypes, newPlugins); return result; } + /** + * Set the {@link #unresolvedIsError} flag. This flag can be set independently from + * {@link #eagerResolving}, i.e., even if eager resolving fails execution is assumed to be + * valid. This allows us for example to process unresolved types/methods/fields even when + * eagerly resolving elements. + */ + public GraphBuilderConfiguration withUnresolvedIsError(boolean newUnresolvedIsError) { + return new GraphBuilderConfiguration(eagerResolving, newUnresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, + plugins); + } + public GraphBuilderConfiguration withEagerResolving(boolean newEagerResolving) { - return new GraphBuilderConfiguration(newEagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins); + return new GraphBuilderConfiguration(newEagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, + plugins); } public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) { - return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, plugins); + return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, + plugins); } public GraphBuilderConfiguration withBytecodeExceptionMode(BytecodeExceptionMode newBytecodeExceptionMode) { - return new GraphBuilderConfiguration(eagerResolving, newBytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins); + return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, newBytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, + plugins); } public GraphBuilderConfiguration withOmitAssertions(boolean newOmitAssertions) { - return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, newOmitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins); + return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, newOmitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, + plugins); } public GraphBuilderConfiguration withFullInfopoints(boolean newInsertFullInfopoints) { ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length); - return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, newInsertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, plugins); + return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, newInsertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, + plugins); } public GraphBuilderConfiguration withNodeSourcePosition(boolean newTrackNodeSourcePosition) { ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length); - return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, newTrackNodeSourcePosition, newSkippedExceptionTypes, plugins); + return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, newTrackNodeSourcePosition, newSkippedExceptionTypes, + plugins); } public ResolvedJavaType[] getSkippedExceptionTypes() { @@ -291,20 +320,16 @@ public class GraphBuilderConfiguration { } public static GraphBuilderConfiguration getDefault(Plugins plugins) { - return new GraphBuilderConfiguration(false, BytecodeExceptionMode.Profile, false, false, false, EMPTY, plugins); + return new GraphBuilderConfiguration(false, false, BytecodeExceptionMode.Profile, false, false, false, EMPTY, plugins); } public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) { - return new GraphBuilderConfiguration(true, BytecodeExceptionMode.OmitAll, false, false, false, EMPTY, plugins); + return new GraphBuilderConfiguration(true, true, BytecodeExceptionMode.OmitAll, false, false, false, EMPTY, plugins); } - /** - * Returns {@code true} if it is an error for a class/field/method resolution to fail. The - * default is the same result as returned by {@link #eagerResolving()}. However, it may be - * overridden to allow failure even when {@link #eagerResolving} is {@code true}. - */ + /** Returns {@code true} if it is an error for a class/field/method resolution to fail. */ public boolean unresolvedIsError() { - return eagerResolving; + return unresolvedIsError; } public Plugins getPlugins() { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java index cdf946f1694..3d5578eaa50 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java @@ -295,4 +295,20 @@ public interface GraphBuilderContext extends GraphBuilderTool { default void notifyReplacedCall(ResolvedJavaMethod targetMethod, ConstantNode node) { } + + /** + * Interface whose instances hold inlining information about the current context, in a wider + * sense. The wider sense in this case concerns graph building approaches that don't necessarily + * keep a chain of {@link GraphBuilderContext} instances normally available through + * {@linkplain #getParent()}. Examples of such approaches are partial evaluation and incremental + * inlining. + */ + interface ExternalInliningContext { + int getInlinedDepth(); + } + + default ExternalInliningContext getExternalInliningContext() { + return null; + } + } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvokeDynamicPlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvokeDynamicPlugin.java new file mode 100644 index 00000000000..4e1e7ac9abb --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvokeDynamicPlugin.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017, 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 org.graalvm.compiler.nodes.graphbuilderconf; + +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.ValueNode; + +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.JavaConstant; + +/** + * {@link GraphBuilderPlugin} interface for static compilation mode, allowing references to dynamic + * types. + */ +public interface InvokeDynamicPlugin extends GraphBuilderPlugin { + + /** + * Checks for a resolved dynamic adapter method at the specified index, resulting from either a + * resolved invokedynamic or invokevirtual on a signature polymorphic MethodHandle method + * (HotSpot invokehandle). + * + * @param builder context for the invoke + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed + * @return {@code true} if a signature polymorphic method reference was found, otherwise + * {@code false} + */ + boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int cpi, int opcode); + + /** + * Checks if this plugin instance supports the specified dynamic invoke. + * + * @param builder context for the invoke + * @param cpi the constant pool index + * @param opcode the opcode of the invoke instruction + * @return {@code true} if this dynamic invoke is supported + */ + boolean supportsDynamicInvoke(GraphBuilderContext builder, int cpi, int opcode); + + /** + * Notifies this object of the value and context of the dynamic method target (e.g., A HotSpot + * adapter method) for a resolved dynamic invoke. + * + * @param builder context for the invoke + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed + * @param target dynamic target method to record + */ + void recordDynamicMethod(GraphBuilderContext builder, int cpi, int opcode, ResolvedJavaMethod target); + + /** + * Notifies this object of the value and context of the dynamic appendix object for a resolved + * dynamic invoke. + * + * @param builder context for the invoke + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed + * @return {@link ValueNode} for appendix constant + */ + ValueNode genAppendixNode(GraphBuilderContext builder, int cpi, int opcode, JavaConstant appendix, FrameState frameState); + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java index c0e4768701b..19b9c608fc1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java @@ -137,8 +137,9 @@ public class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthPr } long offset; if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && componentType.isPrimitive()) { - // On big endian, we do just get expect the type be right aligned in this memory slot - offset = constantOffset - (componentType.getJavaKind().getByteCount() - Math.min(componentType.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount())); + // On big endian, we expect the value to be correctly aligned in memory + int componentByteCount = componentType.getJavaKind().getByteCount(); + offset = constantOffset - (componentByteCount - Math.min(componentByteCount, 4 + expectedEntryKind.getByteCount())); } else { offset = constantOffset; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java index 7c0688d12b1..5fea8c8792a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java @@ -132,11 +132,11 @@ public class PEGraphDecoderTest extends GraalCompilerTest { StructuredGraph targetGraph = null; DebugContext debug = getDebugContext(); try (DebugContext.Scope scope = debug.scope("GraphPETest", testMethod)) { - GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true); + GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true); registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins()); targetGraph = new StructuredGraph.Builder(getInitialOptions(), debug, AllowAssumptions.YES).method(testMethod).build(); CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getTarget().arch, targetGraph, getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES, - null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null); + null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null, null); decoder.decode(testMethod); debug.dump(DebugContext.BASIC_LEVEL, targetGraph, "Target Graph"); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java index 790b7ad18d2..0af78121511 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java @@ -63,9 +63,9 @@ public class CachingPEGraphDecoder extends PEGraphDecoder { public CachingPEGraphDecoder(Architecture architecture, StructuredGraph graph, Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, AllowAssumptions allowAssumptions, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, ParameterPlugin parameterPlugin, - NodePlugin[] nodePlugins) { + NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod) { super(architecture, graph, providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getStampProvider(), loopExplosionPlugin, - invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins); + invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins, callInlinedMethod); this.providers = providers; this.graphBuilderConfig = graphBuilderConfig; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java index 77acf3d0165..5a2be59ea7f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java @@ -238,11 +238,11 @@ public class GraphKit implements GraphBuilderTool { if (frameStateBuilder != null) { if (invoke.getStackKind() != JavaKind.Void) { - frameStateBuilder.push(returnType.getJavaKind(), invoke); + frameStateBuilder.push(invoke.getStackKind(), invoke); } invoke.setStateAfter(frameStateBuilder.create(bci, invoke)); if (invoke.getStackKind() != JavaKind.Void) { - frameStateBuilder.pop(returnType.getJavaKind()); + frameStateBuilder.pop(invoke.getStackKind()); } } return invoke; @@ -475,11 +475,11 @@ public class GraphKit implements GraphBuilderTool { invoke.setNext(noExceptionEdge); if (frameStateBuilder != null) { if (invoke.getStackKind() != JavaKind.Void) { - frameStateBuilder.push(returnType.getJavaKind(), invoke); + frameStateBuilder.push(invoke.getStackKind(), invoke); } invoke.setStateAfter(frameStateBuilder.create(invokeBci, invoke)); if (invoke.getStackKind() != JavaKind.Void) { - frameStateBuilder.pop(returnType.getJavaKind()); + frameStateBuilder.pop(invoke.getStackKind()); } } lastFixedNode = null; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java index a9ad0f2d4fb..1509b364545 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java @@ -193,6 +193,24 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { protected final PEMethodScope methodScope; protected final Invoke invoke; + @Override + public ExternalInliningContext getExternalInliningContext() { + return new ExternalInliningContext() { + @Override + public int getInlinedDepth() { + int count = 0; + PEGraphDecoder.PEMethodScope scope = methodScope; + while (scope != null) { + if (scope.method.equals(callInlinedMethod)) { + count++; + } + scope = scope.caller; + } + return count; + } + }; + } + public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) { this.methodScope = methodScope; this.invoke = invoke; @@ -420,11 +438,12 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { private final NodePlugin[] nodePlugins; private final EconomicMap specialCallTargetCache; private final EconomicMap invocationPluginCache; + private final ResolvedJavaMethod callInlinedMethod; public PEGraphDecoder(Architecture architecture, StructuredGraph graph, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, StampProvider stampProvider, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, ParameterPlugin parameterPlugin, - NodePlugin[] nodePlugins) { + NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod) { super(architecture, graph, metaAccess, constantReflection, constantFieldProvider, stampProvider, true); this.loopExplosionPlugin = loopExplosionPlugin; this.invocationPlugins = invocationPlugins; @@ -433,6 +452,7 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { this.nodePlugins = nodePlugins; this.specialCallTargetCache = EconomicMap.create(Equivalence.DEFAULT); this.invocationPluginCache = EconomicMap.create(Equivalence.DEFAULT); + this.callInlinedMethod = callInlinedMethod; } protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java index eb5d3f9d6f1..067fde637bd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java @@ -224,16 +224,12 @@ public class SnippetTemplate { } /** - * Times instantiations of all templates derived form this snippet. - * - * @see SnippetTemplate#instantiationTimer + * Times instantiations of all templates derived from this snippet. */ private final TimerKey instantiationTimer; /** * Counts instantiations of all templates derived from this snippet. - * - * @see SnippetTemplate#instantiationCounter */ private final CounterKey instantiationCounter; @@ -706,8 +702,6 @@ public class SnippetTemplate { Object[] constantArgs = getConstantArgs(args); StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, args.info.original, constantArgs); - instantiationTimer = DebugContext.timer("SnippetTemplateInstantiationTime[%#s]", args); - instantiationCounter = DebugContext.counter("SnippetTemplateInstantiationCount[%#s]", args); ResolvedJavaMethod method = snippetGraph.method(); Signature signature = method.getSignature(); @@ -1077,20 +1071,6 @@ public class SnippetTemplate { */ private final ArrayList nodes; - /** - * Times instantiations of this template. - * - * @see SnippetInfo#instantiationTimer - */ - private final TimerKey instantiationTimer; - - /** - * Counts instantiations of this template. - * - * @see SnippetInfo#instantiationCounter - */ - private final CounterKey instantiationCounter; - /** * Gets the instantiation-time bindings to this template's parameters. * @@ -1406,9 +1386,8 @@ public class SnippetTemplate { public UnmodifiableEconomicMap instantiate(MetaAccessProvider metaAccess, FixedNode replacee, UsageReplacer replacer, Arguments args, boolean killReplacee) { DebugContext debug = replacee.getDebug(); assert assertSnippetKills(replacee); - try (DebugCloseable a = args.info.instantiationTimer.start(debug); DebugCloseable b = instantiationTimer.start(debug)) { + try (DebugCloseable a = args.info.instantiationTimer.start(debug)) { args.info.instantiationCounter.increment(debug); - instantiationCounter.increment(debug); // Inline the snippet nodes, replacing parameters with the given args in the process StartNode entryPointNode = snippet.start(); FixedNode firstCFGNode = entryPointNode.next(); @@ -1561,7 +1540,6 @@ public class SnippetTemplate { assert assertSnippetKills(replacee); try (DebugCloseable a = args.info.instantiationTimer.start(debug)) { args.info.instantiationCounter.increment(debug); - instantiationCounter.increment(debug); // Inline the snippet nodes, replacing parameters with the given args in the process StartNode entryPointNode = snippet.start(); @@ -1614,7 +1592,6 @@ public class SnippetTemplate { assert assertSnippetKills(replacee); try (DebugCloseable a = args.info.instantiationTimer.start(debug)) { args.info.instantiationCounter.increment(debug); - instantiationCounter.increment(debug); // Inline the snippet nodes, replacing parameters with the given args in the process StartNode entryPointNode = snippet.start(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java index 9c6fb41e70d..9bd73d2d322 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java @@ -30,6 +30,7 @@ import static jdk.vm.ci.code.MemoryBarriers.LOAD_LOAD; import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE; import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD; import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE; +import static org.graalvm.compiler.nodes.NamedLocationIdentity.OFF_HEAP_LOCATION; import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; import java.lang.reflect.Array; @@ -650,7 +651,7 @@ public class StandardGraphBuilderPlugins { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address) { // Emits a null-check for the otherwise unused receiver unsafe.get(); - b.addPush(returnKind, new UnsafeMemoryLoadNode(address, returnKind, LocationIdentity.any())); + b.addPush(returnKind, new UnsafeMemoryLoadNode(address, returnKind, OFF_HEAP_LOCATION)); b.getGraph().markUnsafeAccess(); return true; } @@ -662,7 +663,8 @@ public class StandardGraphBuilderPlugins { if (isVolatile) { b.add(new MembarNode(JMM_PRE_VOLATILE_READ)); } - b.addPush(returnKind, new RawLoadNode(object, offset, returnKind, LocationIdentity.any())); + LocationIdentity locationIdentity = object.isNullConstant() ? OFF_HEAP_LOCATION : LocationIdentity.any(); + b.addPush(returnKind, new RawLoadNode(object, offset, returnKind, locationIdentity)); if (isVolatile) { b.add(new MembarNode(JMM_POST_VOLATILE_READ)); } @@ -685,7 +687,7 @@ public class StandardGraphBuilderPlugins { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value) { // Emits a null-check for the otherwise unused receiver unsafe.get(); - b.add(new UnsafeMemoryStoreNode(address, value, kind, LocationIdentity.any())); + b.add(new UnsafeMemoryStoreNode(address, value, kind, OFF_HEAP_LOCATION)); b.getGraph().markUnsafeAccess(); return true; } @@ -697,7 +699,8 @@ public class StandardGraphBuilderPlugins { if (isVolatile) { b.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); } - b.add(new RawStoreNode(object, offset, value, kind, LocationIdentity.any())); + LocationIdentity locationIdentity = object.isNullConstant() ? OFF_HEAP_LOCATION : LocationIdentity.any(); + b.add(new RawStoreNode(object, offset, value, kind, locationIdentity)); if (isVolatile) { b.add(new MembarNode(JMM_POST_VOLATILE_WRITE)); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java index 4d48fbc2ea1..b4722d8f9b5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java @@ -25,6 +25,8 @@ package org.graalvm.compiler.virtual.phases.ea; import java.util.Iterator; import java.util.List; +import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.nodes.FieldLocationIdentity; import org.graalvm.compiler.nodes.ValueNode; @@ -49,11 +51,15 @@ public final class PEReadEliminationBlockState extends PartialEscapeBlockState

    values) { if (virtual instanceof VirtualInstanceNode) { VirtualInstanceNode instance = (VirtualInstanceNode) virtual; for (int i = 0; i < instance.entryCount(); i++) { - readCache.put(new ReadCacheEntry(new FieldLocationIdentity(instance.field(i)), representation, -1, instance.field(i).getJavaKind()), values.get(i)); + JavaKind declaredKind = instance.field(i).getJavaKind(); + if (declaredKind == stampToJavaKind(values.get(i).stamp())) { + // We won't cache unaligned field writes upon instantiation unless we add + // support for non-array objects in PEReadEliminationClosure.processUnsafeLoad. + readCache.put(new ReadCacheEntry(new FieldLocationIdentity(instance.field(i)), representation, -1, declaredKind, false), values.get(i)); + } } } } @@ -112,7 +144,7 @@ public final class PEReadEliminationBlockState extends PartialEscapeBlockState

    closure) { + public void addReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, boolean overflowAccess, ValueNode value, PartialEscapeClosure closure) { ValueNode cacheObject; ObjectState obj = closure.getObjectState(this, object); if (obj != null) { @@ -121,7 +153,7 @@ public final class PEReadEliminationBlockState extends PartialEscapeBlockState

    closure) { @@ -133,7 +165,7 @@ public final class PEReadEliminationBlockState extends PartialEscapeBlockState

    iter = readCache.getKeys().iterator(); while (iter.hasNext()) { ReadCacheEntry entry = iter.next(); - if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index)) { + if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index || entry.overflowAccess)) { iter.remove(); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java index 88d72712673..b667a19c72f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java @@ -31,7 +31,6 @@ import java.util.List; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; -import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.FieldLocationIdentity; @@ -131,9 +130,10 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure declaredKind.getBitCount() : true; + } + private boolean processUnsafeLoad(RawLoadNode load, PEReadEliminationBlockState state, GraphEffectList effects) { if (load.offset().isConstant()) { ResolvedJavaType type = StampTool.typeOrNull(load.object()); if (type != null && type.isArray()) { + JavaKind accessKind = load.accessKind(); + JavaKind componentKind = type.getComponentType().getJavaKind(); long offset = load.offset().asJavaConstant().asLong(); - int index = VirtualArrayNode.entryIndexForOffset(offset, load.accessKind(), type.getComponentType(), Integer.MAX_VALUE); + int index = VirtualArrayNode.entryIndexForOffset(offset, accessKind, type.getComponentType(), Integer.MAX_VALUE); ValueNode object = GraphUtil.unproxify(load.object()); - LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind()); - ValueNode cachedValue = state.getReadCache(object, location, index, load.accessKind(), this); - if (cachedValue != null && load.stamp().isCompatible(cachedValue.stamp())) { + LocationIdentity location = NamedLocationIdentity.getArrayLocation(componentKind); + ValueNode cachedValue = state.getReadCache(object, location, index, accessKind, this); + assert cachedValue == null || load.stamp().isCompatible(cachedValue.stamp()) : "The RawLoadNode's stamp is not compatible with the cached value."; + if (cachedValue != null) { effects.replaceAtUsages(load, cachedValue, load); addScalarAlias(load, cachedValue); return true; } else { - state.addReadCache(object, location, index, load.accessKind(), load, this); + state.addReadCache(object, location, index, accessKind, isOverflowAccess(accessKind, componentKind), load, this); } } } @@ -196,11 +205,14 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure pair = firstValueSet.get(object); while (pair != null) { - initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, entry.kind, initialState.getReadCache().get(entry), this); + initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, entry.kind, entry.overflowAccess, initialState.getReadCache().get(entry), this); pair = (Pair) pair.getRight(); } } @@ -386,14 +429,14 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure states) { + private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, JavaKind kind, boolean overflowAccess, List states) { ValueNode[] values = new ValueNode[states.size()]; values[0] = states.get(0).getReadCache(getPhiValueAt(phi, 0), identity, index, kind, PEReadEliminationClosure.this); if (values[0] != null) { @@ -407,12 +450,12 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure { } /** - * Constructs a new option key given a default value and option key. The default value and the - * type must not be null. + * Constructs a new option key given a default value and option key. * * @since 1.0 */ public OptionKey(T defaultValue, OptionType type) { - Objects.requireNonNull(defaultValue); Objects.requireNonNull(type); this.defaultValue = defaultValue; this.type = type; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionType.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionType.java index 3beb99fcb73..d1533db49db 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionType.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionType.java @@ -57,7 +57,6 @@ public final class OptionType { */ public OptionType(String name, T defaultValue, Function stringConverter, Consumer validator) { Objects.requireNonNull(name); - Objects.requireNonNull(defaultValue); Objects.requireNonNull(stringConverter); Objects.requireNonNull(validator); this.name = name; @@ -133,7 +132,7 @@ public final class OptionType { return "OptionType[name=" + name + ", defaultValue=" + defaultValue + "]"; } - private static Map, OptionType> DEFAULTTYPES = new HashMap<>(); + private static final Map, OptionType> DEFAULTTYPES = new HashMap<>(); static { DEFAULTTYPES.put(Boolean.class, new OptionType<>("Boolean", false, new Function() { public Boolean apply(String t) { @@ -200,13 +199,24 @@ public final class OptionType { /** * Returns the default option type for a given value. Returns null if no default - * option type is available for this Java type. + * option type is available for the Java type of this value. * * @since 1.0 */ @SuppressWarnings("unchecked") - public static OptionType defaultType(Object value) { - return (OptionType) DEFAULTTYPES.get(value.getClass()); + public static OptionType defaultType(T value) { + return defaultType((Class) value.getClass()); + } + + /** + * Returns the default option type for a class. Returns null if no default option + * type is available for this Java type. + * + * @since 1.0 + */ + @SuppressWarnings("unchecked") + public static OptionType defaultType(Class clazz) { + return (OptionType) DEFAULTTYPES.get(clazz); } } diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c b/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c index 075dedacbb1..4ed1d5abf71 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c @@ -1301,6 +1301,9 @@ debugInit_exit(jvmtiError error, const char *msg) { enum exit_codes { EXIT_NO_ERRORS = 0, EXIT_JVMTI_ERROR = 1, EXIT_TRANSPORT_ERROR = 2 }; + // Release commandLoop vmDeathLock if necessary + commandLoop_exitVmDeathLockOnError(); + // Prepare to exit. Log error and finish logging LOG_MISC(("Exiting with error %s(%d): %s", jvmtiErrorText(error), error, ((msg == NULL) ? "" : msg))); diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c index f78232e1229..2fc3d1b82d3 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, 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 @@ -1287,11 +1287,11 @@ cbVMDeath(jvmtiEnv *jvmti_env, JNIEnv *env) } debugMonitorExit(callbackBlock); /* - * The VM will die soon after the completion of this callback - we - * may need to do a final synchronization with the command loop to - * avoid the VM terminating with replying to the final (resume) - * command. + * The VM will die soon after the completion of this callback - + * we synchronize with both the command loop and the debug loop + * for a more orderly shutdown. */ + commandLoop_sync(); debugLoop_sync(); LOG_MISC(("END cbVMDeath")); diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c b/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c index bd5f080ba37..f301cdc63e3 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c @@ -29,6 +29,9 @@ #include "threadControl.h" #include "invoker.h" + +#define COMMAND_LOOP_THREAD_NAME "JDWP Event Helper Thread" + /* * Event helper thread command commandKinds */ @@ -121,6 +124,9 @@ static CommandQueue commandQueue; static jrawMonitorID commandQueueLock; static jrawMonitorID commandCompleteLock; static jrawMonitorID blockCommandLoopLock; +static jrawMonitorID vmDeathLock; +static volatile jboolean commandLoopEnteredVmDeathLock = JNI_FALSE; + static jint maxQueueSize = 50 * 1024; /* TO DO: Make this configurable */ static jboolean holdEvents; static jint currentQueueSize = 0; @@ -700,9 +706,15 @@ commandLoop(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg) * handleCommand() to prevent any races. */ jboolean doBlock = needBlockCommandLoop(command); - log_debugee_location("commandLoop(): command being handled", NULL, NULL, 0); - handleCommand(jni_env, command); + debugMonitorEnter(vmDeathLock); + commandLoopEnteredVmDeathLock = JNI_TRUE; + if (!gdata->vmDead) { + log_debugee_location("commandLoop(): command being handled", NULL, NULL, 0); + handleCommand(jni_env, command); + } completeCommand(command); + debugMonitorExit(vmDeathLock); + commandLoopEnteredVmDeathLock = JNI_FALSE; /* if we just finished a suspend-all cmd, then we block here */ if (doBlock) { doBlockCommandLoop(); @@ -725,10 +737,11 @@ eventHelper_initialize(jbyte sessionID) commandQueueLock = debugMonitorCreate("JDWP Event Helper Queue Monitor"); commandCompleteLock = debugMonitorCreate("JDWP Event Helper Completion Monitor"); blockCommandLoopLock = debugMonitorCreate("JDWP Event Block CommandLoop Monitor"); + vmDeathLock = debugMonitorCreate("JDWP VM_DEATH CommandLoop Monitor"); /* Start the event handler thread */ func = &commandLoop; - (void)spawnNewThread(func, NULL, "JDWP Event Helper Thread"); + (void)spawnNewThread(func, NULL, COMMAND_LOOP_THREAD_NAME); } void @@ -759,6 +772,42 @@ eventHelper_unlock(void) debugMonitorExit(commandQueueLock); } +void commandLoop_exitVmDeathLockOnError() +{ + const char* MSG_BASE = "exitVmDeathLockOnError: error in JVMTI %s: %d\n"; + jthread cur_thread = NULL; + jvmtiThreadInfo thread_info; + jvmtiError err = JVMTI_ERROR_NONE; + + err = JVMTI_FUNC_PTR(gdata->jvmti, GetCurrentThread) + (gdata->jvmti, &cur_thread); + if (err != JVMTI_ERROR_NONE) { + LOG_ERROR((MSG_BASE, "GetCurrentThread", err)); + return; + } + + err = JVMTI_FUNC_PTR(gdata->jvmti, GetThreadInfo) + (gdata->jvmti, cur_thread, &thread_info); + if (err != JVMTI_ERROR_NONE) { + LOG_ERROR((MSG_BASE, "GetThreadInfo", err)); + return; + } + if (strcmp(thread_info.name, COMMAND_LOOP_THREAD_NAME) != 0) { + return; + } + if (commandLoopEnteredVmDeathLock == JNI_TRUE) { + debugMonitorExit(vmDeathLock); + commandLoopEnteredVmDeathLock = JNI_FALSE; + } +} + +void +commandLoop_sync(void) +{ + debugMonitorEnter(vmDeathLock); + debugMonitorExit(vmDeathLock); +} + /* Change all references to global in the EventInfo struct */ static void saveEventInfoRefs(JNIEnv *env, EventInfo *evinfo) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.h b/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.h index fcc4e86f337..8387cb0f3da 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, 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 @@ -54,6 +54,9 @@ void eventHelper_releaseEvents(void); void eventHelper_lock(void); void eventHelper_unlock(void); +void commandLoop_sync(void); /* commandLoop sync with cbVMDeath */ +void commandLoop_exitVmDeathLockOnError(void); + /* * Private interface for coordinating between eventHelper.c: commandLoop() * and ThreadReferenceImpl.c: resume() and VirtualMachineImpl.c: resume(). diff --git a/src/jdk.management.agent/unix/native/libmanagement_agent/FileSystemImpl.c b/src/jdk.management.agent/unix/native/libmanagement_agent/FileSystemImpl.c index ba780592811..ad3f7b95473 100644 --- a/src/jdk.management.agent/unix/native/libmanagement_agent/FileSystemImpl.c +++ b/src/jdk.management.agent/unix/native/libmanagement_agent/FileSystemImpl.c @@ -45,7 +45,7 @@ JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *vm, void *reserved) return JNI_EVERSION; /* JNI version not supported */ } - return JNI_VERSION_9; + return JNI_VERSION_10; } /* diff --git a/src/jdk.management.agent/windows/native/libmanagement_agent/FileSystemImpl.c b/src/jdk.management.agent/windows/native/libmanagement_agent/FileSystemImpl.c index 62ad33c78b8..ea6559c2a3a 100644 --- a/src/jdk.management.agent/windows/native/libmanagement_agent/FileSystemImpl.c +++ b/src/jdk.management.agent/windows/native/libmanagement_agent/FileSystemImpl.c @@ -39,7 +39,7 @@ JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *vm, void *reserved) return JNI_EVERSION; /* JNI version not supported */ } - return JNI_VERSION_9; + return JNI_VERSION_10; } diff --git a/src/jdk.management/share/native/libmanagement_ext/management_ext.c b/src/jdk.management/share/native/libmanagement_ext/management_ext.c index dbb9f027137..02285521042 100644 --- a/src/jdk.management/share/native/libmanagement_ext/management_ext.c +++ b/src/jdk.management/share/native/libmanagement_ext/management_ext.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -44,7 +44,7 @@ JNIEXPORT jint JNICALL return JNI_ERR; } - jmm_interface = (JmmInterface*) JVM_GetManagement(JMM_VERSION_1_0); + jmm_interface = (JmmInterface*) JVM_GetManagement(JMM_VERSION); if (jmm_interface == NULL) { JNU_ThrowInternalError(env, "Unsupported Management version"); return JNI_ERR; diff --git a/test/hotspot/gtest/gtestLauncher.cpp b/test/hotspot/gtest/gtestLauncher.cpp index dc94c7998ca..f926af6ed09 100644 --- a/test/hotspot/gtest/gtestLauncher.cpp +++ b/test/hotspot/gtest/gtestLauncher.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -21,7 +21,7 @@ * questions. */ -#include "prims/jni.h" +#include "jni.h" extern "C" { JNIIMPORT void JNICALL runUnitTests(int argv, char** argc); diff --git a/test/hotspot/gtest/gtestMain.cpp b/test/hotspot/gtest/gtestMain.cpp index e3dcf32b7ed..ec92abb72c8 100644 --- a/test/hotspot/gtest/gtestMain.cpp +++ b/test/hotspot/gtest/gtestMain.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -35,7 +35,7 @@ #include #endif -#include "prims/jni.h" +#include "jni.h" #include "unittest.hpp" // Default value for -new-thread option: true on AIX because we run into @@ -319,4 +319,3 @@ JNIEXPORT void JNICALL runUnitTests(int argc, char** argv) { runUnitTestsInner(argc, argv); } } - diff --git a/test/hotspot/gtest/runtime/test_perfdata.cpp b/test/hotspot/gtest/runtime/test_perfdata.cpp new file mode 100644 index 00000000000..d1a5db39e9c --- /dev/null +++ b/test/hotspot/gtest/runtime/test_perfdata.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, 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 "precompiled.hpp" +#include "runtime/perfMemory.hpp" +#include "unittest.hpp" + +class PerfMemoryTest : public ::testing::Test { + public: + static char* top() { return PerfMemory::_top; } + static PerfDataPrologue* prologue() { return PerfMemory::_prologue; } +}; + +TEST_VM_F(PerfMemoryTest, destroy) { + PerfMemory::destroy(); + + ASSERT_NE(PerfMemory::start(), (char*)NULL) << "PerfMemory::_start should not be NULL"; + ASSERT_NE(PerfMemory::end(), (char*)NULL) << "PerfMemory::_end should not be NULL"; + ASSERT_NE(PerfMemoryTest::top(), (char*)NULL) << "PerfMemory::_top should not be NULL"; + ASSERT_NE(PerfMemoryTest::prologue(), (PerfDataPrologue*)NULL) << "PerfMemory::_prologue should not be NULL"; + ASSERT_NE(PerfMemory::capacity(), (size_t)0) << "PerfMemory::_capacity should not be 0"; +} + diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index 1fcc8610f36..69eca8ec107 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -52,7 +52,9 @@ requires.properties= \ vm.rtm.cpu \ vm.rtm.os \ vm.aot \ - vm.cds + vm.cds \ + vm.graal.enabled \ + docker.support # Minimum jtreg version requiredVersion=4.2 b08 diff --git a/test/hotspot/jtreg/compiler/aot/AotCompiler.java b/test/hotspot/jtreg/compiler/aot/AotCompiler.java index 9a3654b1355..5c230309013 100644 --- a/test/hotspot/jtreg/compiler/aot/AotCompiler.java +++ b/test/hotspot/jtreg/compiler/aot/AotCompiler.java @@ -145,13 +145,37 @@ public class AotCompiler { + " [-compile ]* [-extraopt ]*"); } + // runs ld -v (or ld -V on solaris) and check its exit code + private static boolean checkLd(Path bin) { + try { + return 0 == ProcessTools.executeCommand(bin.toString(), + Platform.isSolaris() ? "-V" : "-v") + .getExitValue(); + } catch (Throwable t) { + // any errors mean ld doesn't work + return false; + } + } + public static String resolveLinker() { Path linker = null; - // 1st, check if PATH has ld - for (String path : System.getenv("PATH").split(File.pathSeparator)) { - if (Files.exists(Paths.get(path).resolve("ld"))) { - // there is ld in PATH, jaotc is supposed to find it by its own - return null; + // if non windows, 1st, check if PATH has ld + if (!Platform.isWindows()) { + String bin = "ld"; + for (String path : System.getenv("PATH").split(File.pathSeparator)) { + Path ld = Paths.get(path).resolve("ld"); + if (Files.exists(ld)) { + // there is ld in PATH + if (checkLd(ld)) { + System.out.println("found working linker: " + ld); + // ld works, jaotc is supposed to find and use it + return null; + } else { + System.out.println("found broken linker: " + ld); + // ld exists in PATH, but doesn't work, have to use devkit + break; + } + } } } // there is no ld in PATH, will use ld from devkit @@ -275,7 +299,9 @@ public class AotCompiler { } } } catch (FileNotFoundException e) { - throw new Error("artifact resolution error: " + e, e); + System.err.println("artifact resolution error: " + e); + // let jaotc try to find linker + return null; } if (linker != null) { return linker.toAbsolutePath().toString(); diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java index b36c27282ef..3100abf237c 100644 --- a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java +++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java @@ -25,7 +25,6 @@ * @test * @requires vm.aot * @library /test/lib /testlibrary / - * @ignore 8132547 * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc * @build compiler.calls.common.InvokeDynamic diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java index 6b9c07a45c1..187d9983f3e 100644 --- a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java +++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java @@ -25,7 +25,6 @@ * @test * @requires vm.aot * @library /test/lib /testlibrary / - * @ignore 8132547 * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc * @build compiler.calls.common.InvokeDynamic diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java index 2707471802f..8571be843ad 100644 --- a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java +++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java @@ -25,7 +25,6 @@ * @test * @requires vm.aot * @library /test/lib /testlibrary / - * @ignore 8132547 * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc * @build compiler.calls.common.InvokeDynamic diff --git a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java index d7808120cda..668c10ecc03 100644 --- a/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java +++ b/test/hotspot/jtreg/compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java @@ -25,7 +25,6 @@ * @test * @requires vm.aot * @library /test/lib /testlibrary / - * @ignore 8132547 * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc * @build compiler.calls.common.InvokeDynamic diff --git a/test/hotspot/jtreg/compiler/aot/scripts/test-javac.sh b/test/hotspot/jtreg/compiler/aot/scripts/test-javac.sh index feb3ae369e6..57f5bfd2b2f 100644 --- a/test/hotspot/jtreg/compiler/aot/scripts/test-javac.sh +++ b/test/hotspot/jtreg/compiler/aot/scripts/test-javac.sh @@ -108,7 +108,7 @@ for i in `seq 1 $N`; do done NAME="jvmci" -DIR="$DIR/../../../../src/jdk.internal.vm.ci" +DIR="$DIR/../../../../../../src/jdk.internal.vm.ci" FILES=`find $DIR -type f -name '*.java'` COUNT=`find $DIR -type f -name '*.java' | wc -l` diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyNoInitDeopt.java b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyNoInitDeopt.java index 023bd266f31..34ff2e13393 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyNoInitDeopt.java +++ b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyNoInitDeopt.java @@ -25,7 +25,7 @@ * @test * @bug 8072016 * @summary Infinite deoptimization/recompilation cycles in case of arraycopy with tightly coupled allocation - * @requires vm.flavor == "server" & !vm.emulatedClient + * @requires vm.flavor == "server" & !vm.emulatedClient & !vm.graal.enabled * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/compiler/c2/Test8004741.java b/test/hotspot/jtreg/compiler/c2/Test8004741.java index f52a68e0090..69d2ad9f0bd 100644 --- a/test/hotspot/jtreg/compiler/c2/Test8004741.java +++ b/test/hotspot/jtreg/compiler/c2/Test8004741.java @@ -26,6 +26,7 @@ * @bug 8004741 * @summary Missing compiled exception handle table entry for multidimensional array allocation * + * @requires !vm.graal.enabled * @run main/othervm -Xmx64m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions * -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers * -XX:+SafepointALot -XX:GuaranteedSafepointInterval=100 diff --git a/test/hotspot/jtreg/compiler/ciReplay/TestDumpReplay.java b/test/hotspot/jtreg/compiler/ciReplay/TestDumpReplay.java new file mode 100644 index 00000000000..d1f03a8429e --- /dev/null +++ b/test/hotspot/jtreg/compiler/ciReplay/TestDumpReplay.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2017, 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. + */ + +/* + * @test + * @library /test/lib + * @modules java.base/jdk.internal.misc:+open + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xbatch -XX:-TieredCompilation -XX:+AlwaysIncrementalInline + * -XX:CompileCommand=compileonly,compiler.ciReplay.TestDumpReplay::* + * compiler.ciReplay.TestDumpReplay + */ + +package compiler.ciReplay; + +import sun.hotspot.WhiteBox; + +public class TestDumpReplay { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + private static final String emptyString; + + static { + emptyString = ""; + } + + public static void m1() { + m2(); + } + + public static void m2() { + m3(); + } + + public static void m3() { + + } + + public static void main(String[] args) { + // Add compiler control directive to force generation of replay file + String directive = "[{ match: \"*.*\", DumpReplay: true }]"; + if (WHITE_BOX.addCompilerDirective(directive) != 1) { + throw new RuntimeException("Failed to add compiler directive"); + } + + // Trigger compilation of m1 + for (int i = 0; i < 10_000; ++i) { + m1(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java b/test/hotspot/jtreg/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java index 0c41ba78d3a..76559944c7c 100644 --- a/test/hotspot/jtreg/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java +++ b/test/hotspot/jtreg/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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 @@ -22,13 +22,16 @@ */ /* - * @test TestAnonymousClassUnloading + * @test * @bug 8054402 * @summary "Tests unloading of anonymous classes." * @library /test/lib / * @modules java.base/jdk.internal.misc + * @build sun.hotspot.WhiteBox + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * - * @run main/othervm/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:-BackgroundCompilation * compiler.classUnloading.anonymousClass.TestAnonymousClassUnloading */ diff --git a/test/hotspot/jtreg/compiler/compilercontrol/jcmd/PrintDirectivesTest.java b/test/hotspot/jtreg/compiler/compilercontrol/jcmd/PrintDirectivesTest.java index 335e89c6668..2f8f4abc9f4 100644 --- a/test/hotspot/jtreg/compiler/compilercontrol/jcmd/PrintDirectivesTest.java +++ b/test/hotspot/jtreg/compiler/compilercontrol/jcmd/PrintDirectivesTest.java @@ -27,7 +27,7 @@ * @summary Tests jcmd to be able to add a directive to compile only specified methods * @modules java.base/jdk.internal.misc * @library /test/lib / - * @requires vm.flavor != "minimal" + * @requires vm.flavor != "minimal" & !vm.graal.enabled * * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox diff --git a/test/hotspot/jtreg/compiler/compilercontrol/logcompilation/LogTest.java b/test/hotspot/jtreg/compiler/compilercontrol/logcompilation/LogTest.java index b681029061a..97650e9fbf6 100644 --- a/test/hotspot/jtreg/compiler/compilercontrol/logcompilation/LogTest.java +++ b/test/hotspot/jtreg/compiler/compilercontrol/logcompilation/LogTest.java @@ -25,6 +25,8 @@ * @test * @bug 8137167 * @summary Tests LogCompilation executed standalone without log commands or directives + * + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.misc * @library /test/lib / * diff --git a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java index b4f62daa762..ac17e567b09 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java +++ b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java @@ -26,7 +26,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.cpu.features ~= ".*aes.*" + * @requires vm.cpu.features ~= ".*aes.*" & !vm.graal.enabled * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/exceptions/TestC1ExceptionHandlersSameBCI.java b/test/hotspot/jtreg/compiler/exceptions/TestC1ExceptionHandlersSameBCI.java new file mode 100644 index 00000000000..44346d9a7f6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/exceptions/TestC1ExceptionHandlersSameBCI.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017, Red Hat, Inc. 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. + */ + +/** + * @test + * @bug 8188151 + * @summary assert failure with 2 handlers at same bci + * @run main/othervm -XX:-BackgroundCompilation -XX:CompileOnly=TestC1ExceptionHandlersSameBCI::test1 -XX:CompileOnly=TestC1ExceptionHandlersSameBCI::test2 -XX:CompileCommand=dontinline,TestC1ExceptionHandlersSameBCI::not_inline1 -XX:CompileCommand=dontinline,TestC1ExceptionHandlersSameBCI::not_inline2 TestC1ExceptionHandlersSameBCI + * + */ + +public class TestC1ExceptionHandlersSameBCI { + static class Ex1 extends Exception { + + } + static class Ex2 extends Exception { + + } + + static void not_inline1() throws Ex1, Ex2 { + + } + + static void not_inline2(int v) { + + } + + static void test1() throws Ex1, Ex2 { + int i = 0; + try { + not_inline1(); + i = 1; + not_inline1(); + } catch (Ex1|Ex2 ex) { + not_inline2(i); + } + } + + static void test2() { + int i = 0; + try { + test1(); + i = 1; + test1(); + } catch (Ex1|Ex2 ex) { + not_inline2(i); + } + } + + static public void main(String[] args) { + for (int i = 0; i < 5000; i++) { + test2(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/intrinsics/IntrinsicDisabledTest.java b/test/hotspot/jtreg/compiler/intrinsics/IntrinsicDisabledTest.java index aed0acab0ab..14edaf4e495 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/IntrinsicDisabledTest.java +++ b/test/hotspot/jtreg/compiler/intrinsics/IntrinsicDisabledTest.java @@ -24,6 +24,8 @@ /* * @test * @bug 8138651 + * + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.misc * @library /test/lib / * diff --git a/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java b/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java index 3285b904bf7..c31a87a46a2 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java +++ b/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java @@ -25,7 +25,7 @@ * @test NullCheckDroppingsTest * @bug 8054492 * @summary Casting can result in redundant null checks in generated code - * @requires vm.flavor == "server" & !vm.emulatedClient + * @requires vm.flavor == "server" & !vm.emulatedClient & !vm.graal.enabled * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java index 698afa06de0..2ecaf5f9d28 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java +++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java @@ -42,7 +42,8 @@ public class GenericTestCaseForOtherCPU extends new OrPredicate(Platform::isAArch64, new OrPredicate(Platform::isS390x, new OrPredicate(Platform::isSparc, - new OrPredicate(Platform::isX64, Platform::isX86)))))); + new OrPredicate(Platform::isPPC, + new OrPredicate(Platform::isX64, Platform::isX86))))))); } @Override diff --git a/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java b/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java index d01e8c177dd..79c9cd7891f 100644 --- a/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java +++ b/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -308,10 +308,6 @@ public class CompilerToVMHelper { return CompilerToVM.class; } - public static Class HotSpotConstantPoolClass() { - return HotSpotConstantPool.class; - } - public static Class getMirror(HotSpotResolvedObjectType type) { return ((HotSpotResolvedJavaType) type).mirror(); } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java index 135bb9284d1..8afc7d7b98e 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -110,7 +110,7 @@ public class DataPatchTest extends CodeInstallationTest { test(asm -> { ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass()); Register klass = asm.emitLoadPointer((HotSpotConstant) constantReflection.asObjectHub(type)); - Register ret = asm.emitLoadPointer(klass, config.classMirrorOffset); + Register ret = asm.emitLoadPointer(asm.emitLoadPointer(klass, config.classMirrorHandleOffset), 0); asm.emitPointerRet(ret); }); } @@ -123,7 +123,7 @@ public class DataPatchTest extends CodeInstallationTest { HotSpotConstant hub = (HotSpotConstant) constantReflection.asObjectHub(type); Register narrowKlass = asm.emitLoadPointer((HotSpotConstant) hub.compress()); Register klass = asm.emitUncompressPointer(narrowKlass, config.narrowKlassBase, config.narrowKlassShift); - Register ret = asm.emitLoadPointer(klass, config.classMirrorOffset); + Register ret = asm.emitLoadPointer(asm.emitLoadPointer(klass, config.classMirrorHandleOffset), 0); asm.emitPointerRet(ret); }); } @@ -135,7 +135,7 @@ public class DataPatchTest extends CodeInstallationTest { HotSpotConstant hub = (HotSpotConstant) constantReflection.asObjectHub(type); DataSectionReference ref = asm.emitDataItem(hub); Register klass = asm.emitLoadPointer(ref); - Register ret = asm.emitLoadPointer(klass, config.classMirrorOffset); + Register ret = asm.emitLoadPointer(asm.emitLoadPointer(klass, config.classMirrorHandleOffset), 0); asm.emitPointerRet(ret); }); } @@ -150,7 +150,7 @@ public class DataPatchTest extends CodeInstallationTest { DataSectionReference ref = asm.emitDataItem(narrowHub); Register narrowKlass = asm.emitLoadNarrowPointer(ref); Register klass = asm.emitUncompressPointer(narrowKlass, config.narrowKlassBase, config.narrowKlassShift); - Register ret = asm.emitLoadPointer(klass, config.classMirrorOffset); + Register ret = asm.emitLoadPointer(asm.emitLoadPointer(klass, config.classMirrorHandleOffset), 0); asm.emitPointerRet(ret); }); } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java index cc80c0bcdbe..71182b1a7bf 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -40,7 +40,7 @@ public class TestHotSpotVMConfig extends HotSpotVMConfigAccess { public final long narrowKlassBase = getFieldValue("CompilerToVM::Data::Universe_narrow_klass_base", Long.class, "address"); public final int narrowKlassShift = getFieldValue("CompilerToVM::Data::Universe_narrow_klass_shift", Integer.class, "int"); - public final int classMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "oop"); + public final int classMirrorHandleOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle"); public final int MARKID_DEOPT_HANDLER_ENTRY = getConstant("CodeInstaller::DEOPT_HANDLER_ENTRY", Integer.class); public final long handleDeoptStub = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", Long.class, "address"); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MemoryAccessProviderData.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MemoryAccessProviderData.java index 1122bd7eb5d..54f5d41ff38 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MemoryAccessProviderData.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MemoryAccessProviderData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -64,7 +64,7 @@ public class MemoryAccessProviderData { @DataProvider(name = "positiveObject") public static Object[][] getPositiveObjectJavaKind() { HotSpotJVMCIRuntimeProvider runtime = (HotSpotJVMCIRuntimeProvider) JVMCI.getRuntime(); - int offset = new HotSpotVMConfigAccess(runtime.getConfigStore()).getFieldOffset("Klass::_java_mirror", Integer.class, "oop"); + int offset = new HotSpotVMConfigAccess(runtime.getConfigStore()).getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle"); Constant wrappedKlassPointer = ((HotSpotResolvedObjectType) runtime.fromClass(TestClass.class)).klass(); return new Object[][]{new Object[]{JavaKind.Object, wrappedKlassPointer, (long) offset, TEST_CLASS_CONSTANT, 0}}; } diff --git a/test/hotspot/jtreg/compiler/loopopts/TestCMovSplitThruPhi.java b/test/hotspot/jtreg/compiler/loopopts/TestCMovSplitThruPhi.java new file mode 100644 index 00000000000..03df3c0b810 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestCMovSplitThruPhi.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017, Red Hat, Inc. 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. + */ + +/** + * @test + * @bug 8187822 + * @summary C2 conditonal move optimization might create broken graph + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestCMovSplitThruPhi::not_inlined -XX:CompileOnly=TestCMovSplitThruPhi::test -XX:-LoopUnswitching TestCMovSplitThruPhi + * + */ + +public class TestCMovSplitThruPhi { + static int f; + + static int test(boolean flag1, boolean flag2, boolean flag3, boolean flag4) { + int v3 = 0; + if (flag4) { + for (int i = 0; i < 10; i++) { + int v1 = 0; + if (flag1) { + v1 = not_inlined(); + } + // AddI below will be candidate for split through Phi + int v2 = v1; + if (flag2) { + v2 = f + v1; + } + // test above will be converted to CMovI + if (flag3) { + v3 = v2 * 2; + break; + } + } + } + return v3; + } + + private static int not_inlined() { + return 0; + } + + public static void main(String[] args) { + for (int i = 0; i < 20000; i++) { + test((i % 2) == 0, (i % 2) == 0, (i % 100) == 1, (i % 1000) == 1); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestMoveStoresOutOfLoops.java b/test/hotspot/jtreg/compiler/loopopts/TestMoveStoresOutOfLoops.java index ed86d36c338..38ce019db08 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestMoveStoresOutOfLoops.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestMoveStoresOutOfLoops.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8080289 + * @bug 8080289 8189067 * @summary Move stores out of loops if possible * * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation @@ -43,6 +43,7 @@ public class TestMoveStoresOutOfLoops { private static long[] array = new long[10]; private static long[] array2 = new long[10]; private static boolean[] array3 = new boolean[1000]; + private static int[] array4 = new int[1000]; private static byte[] byte_array = new byte[10]; // Array store should be moved out of the loop, value stored @@ -108,6 +109,15 @@ public class TestMoveStoresOutOfLoops { } } + // Array store can be moved out of the inner loop + static void test_after_7(int idx) { + for (int i = 0; i < 1000; i++) { + for (int j = 0; j <= 42; j++) { + array4[i] = j; + } + } + } + // Optimize out redundant stores static void test_stores_1(int ignored) { array[0] = 0; @@ -285,6 +295,17 @@ public class TestMoveStoresOutOfLoops { return success; } + static boolean array_check5(String name) { + boolean success = true; + for (int i = 0; i < 1000; i++) { + if (array4[i] != 42) { + success = false; + System.out.println(name + " failed: array[" + i + "] = " + array4[i]); + } + } + return success; + } + static public void main(String[] args) throws Exception { TestMoveStoresOutOfLoops test = new TestMoveStoresOutOfLoops(); test.doTest("test_after_1", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); @@ -295,6 +316,7 @@ public class TestMoveStoresOutOfLoops { test.doTest("test_after_6", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); array3[999] = true; test.doTest("test_after_6", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); + test.doTest("test_after_7", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check5); test.doTest("test_stores_1", TestMoveStoresOutOfLoops::array_init3, TestMoveStoresOutOfLoops::array_check3); test.doTest("test_stores_2", TestMoveStoresOutOfLoops::array_init3, TestMoveStoresOutOfLoops::array_check3); diff --git a/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java b/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java index 111475fcbfd..f23673ad651 100644 --- a/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java +++ b/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java @@ -28,7 +28,7 @@ * @summary Test that C2 flag UseCountedLoopSafepoints ensures a safepoint is kept in a CountedLoop * @library /test/lib / * @requires vm.compMode != "Xint" & vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) & vm.debug == true - * @requires !vm.emulatedClient + * @requires !vm.emulatedClient & !vm.graal.enabled * @modules java.base/jdk.internal.misc * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox diff --git a/src/hotspot/os/windows/decoder_windows.hpp b/test/hotspot/jtreg/compiler/runtime/Test8168712.java similarity index 54% rename from src/hotspot/os/windows/decoder_windows.hpp rename to test/hotspot/jtreg/compiler/runtime/Test8168712.java index d35ffa35113..88926fbf27e 100644 --- a/src/hotspot/os/windows/decoder_windows.hpp +++ b/test/hotspot/jtreg/compiler/runtime/Test8168712.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -19,34 +19,31 @@ * 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. - * */ -#ifndef OS_WINDOWS_VM_DECODER_WINDOWS_HPP -#define OS_WINDOWS_VM_DECIDER_WINDOWS_HPP +/** + * @test + * @requires vm.simpleArch == "x64" & vm.debug + * @bug 8168712 + * + * @run main/othervm -XX:CompileCommand=compileonly,Test8168712.* -XX:CompileCommand=compileonly,*Object.* -XX:+DTraceMethodProbes -XX:-UseOnStackReplacement -XX:+DeoptimizeRandom compiler.runtime.Test8168712 + */ +package compiler.runtime; -#include "utilities/decoder.hpp" +import java.util.*; -class WindowsDecoder : public AbstractDecoder { - -public: - WindowsDecoder(); - virtual ~WindowsDecoder() { uninitialize(); }; - - bool can_decode_C_frame_in_vm() const; - bool demangle(const char* symbol, char *buf, int buflen); - bool decode(address addr, char *buf, int buflen, int* offset, const char* modulepath, bool demangle); - bool decode(address addr, char *buf, int buflen, int* offset, const void* base) { - ShouldNotReachHere(); - return false; - } - -private: - void initialize(); - void uninitialize(); - - bool _can_decode_in_vm; - -}; - -#endif // OS_WINDOWS_VM_DECODER_WINDOWS_HPP +public class Test8168712 { + static HashSet m = new HashSet<>(); + public static void main(String args[]) { + int i = 0; + while (i++<15000) { + test(); + } + } + static Test8168712 test() { + return new Test8168712(); + } + protected void finalize() { + m.add(this); + } +} diff --git a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java index d866377049b..5dce9a1fb4b 100644 --- a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java +++ b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java @@ -71,23 +71,27 @@ public class IntrinsicPredicates { = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] { "sha256" }, null), new OrPredicate(new CPUSpecificPredicate("s390.*", new String[] { "sha256" }, null), new OrPredicate(new CPUSpecificPredicate("sparc.*", new String[] { "sha256" }, null), + new OrPredicate(new CPUSpecificPredicate("ppc64.*", new String[] { "sha" }, null), + new OrPredicate(new CPUSpecificPredicate("ppc64le.*", new String[] { "sha" }, null), // x86 variants new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("i386.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("x86.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] { "avx2", "bmi2" }, null), - new CPUSpecificPredicate("x86_64", new String[] { "avx2", "bmi2" }, null)))))))); + new CPUSpecificPredicate("x86_64", new String[] { "avx2", "bmi2" }, null)))))))))); public static final BooleanSupplier SHA512_INSTRUCTION_AVAILABLE = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] { "sha512" }, null), new OrPredicate(new CPUSpecificPredicate("s390.*", new String[] { "sha512" }, null), new OrPredicate(new CPUSpecificPredicate("sparc.*", new String[] { "sha512" }, null), + new OrPredicate(new CPUSpecificPredicate("ppc64.*", new String[] { "sha" }, null), + new OrPredicate(new CPUSpecificPredicate("ppc64le.*", new String[] { "sha" }, null), // x86 variants new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("i386.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("x86.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] { "avx2", "bmi2" }, null), - new CPUSpecificPredicate("x86_64", new String[] { "avx2", "bmi2" }, null)))))))); + new CPUSpecificPredicate("x86_64", new String[] { "avx2", "bmi2" }, null)))))))))); public static final BooleanSupplier ANY_SHA_INSTRUCTION_AVAILABLE = new OrPredicate(IntrinsicPredicates.SHA1_INSTRUCTION_AVAILABLE, diff --git a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java index 86d15bd65d1..abef68866ab 100644 --- a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java +++ b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java @@ -51,7 +51,7 @@ public abstract class CompilerWhiteBoxTest { public static final int COMP_LEVEL_LIMITED_PROFILE = 2; /** {@code CompLevel::CompLevel_full_profile} -- C1, invocation & backedge counters + mdo */ public static final int COMP_LEVEL_FULL_PROFILE = 3; - /** {@code CompLevel::CompLevel_full_optimization} -- C2 or Shark */ + /** {@code CompLevel::CompLevel_full_optimization} -- C2 */ public static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; /** Maximal value for CompLevel */ public static final int COMP_LEVEL_MAX = COMP_LEVEL_FULL_OPTIMIZATION; diff --git a/test/hotspot/jtreg/gc/logging/TestPrintReferences.java b/test/hotspot/jtreg/gc/logging/TestPrintReferences.java index 2a1bb194b6d..864163354a7 100644 --- a/test/hotspot/jtreg/gc/logging/TestPrintReferences.java +++ b/test/hotspot/jtreg/gc/logging/TestPrintReferences.java @@ -23,7 +23,7 @@ /* * @test TestPrintReferences - * @bug 8136991 8186402 + * @bug 8136991 8186402 8186465 8188245 * @summary Validate the reference processing logging * @key gc * @library /test/lib @@ -32,40 +32,63 @@ */ import java.lang.ref.SoftReference; +import java.math.BigDecimal; import java.util.ArrayList; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; +import java.util.regex.Pattern; +import java.util.regex.Matcher; public class TestPrintReferences { + static String output; + static final String doubleRegex = "[0-9]+[.,][0-9]+"; + static final String referenceProcessing = "Reference Processing"; + static final String softReference = "SoftReference"; + static final String weakReference = "WeakReference"; + static final String finalReference = "FinalReference"; + static final String phantomReference = "PhantomReference"; + static final String phase1 = "Phase1"; + static final String phase2 = "Phase2"; + static final String phase3 = "Phase3"; + static final String gcLogTimeRegex = ".* GC\\([0-9]+\\) "; + public static void main(String[] args) throws Exception { ProcessBuilder pb_enabled = ProcessTools.createJavaProcessBuilder("-Xlog:gc+phases+ref=debug", "-XX:+UseG1GC", - "-Xmx10M", + "-Xmx32M", // Explicit thread setting is required to avoid using only 1 thread "-XX:ParallelGCThreads=2", GCTest.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start()); - String indent_4 = " "; - String indent_6 = " "; - String indent_8 = " "; - String gcLogTimeRegex = ".* GC\\([0-9]+\\) "; + checkLogFormat(output); + checkLogValue(output); + + output.shouldHaveExitValue(0); + } + + static String indent(int count) { + return " {" + count + "}"; + } + + // Find the first Reference Processing log and check its format. + public static void checkLogFormat(OutputAnalyzer output) { String countRegex = "[0-9]+"; - String timeRegex = "[0-9]+[.,][0-9]+ms"; - String totalRegex = gcLogTimeRegex + indent_4 + "Reference Processing: " + timeRegex + "\n"; - String balanceRegex = gcLogTimeRegex + indent_8 + "Balance queues: " + timeRegex + "\n"; - String softRefRegex = gcLogTimeRegex + indent_6 + "SoftReference: " + timeRegex + "\n"; - String weakRefRegex = gcLogTimeRegex + indent_6 + "WeakReference: " + timeRegex + "\n"; - String finalRefRegex = gcLogTimeRegex + indent_6 + "FinalReference: " + timeRegex + "\n"; - String phantomRefRegex = gcLogTimeRegex + indent_6 + "PhantomReference: " + timeRegex + "\n"; - String refDetailRegex = gcLogTimeRegex + indent_8 + "Phase2: " + timeRegex + "\n" + - gcLogTimeRegex + indent_8 + "Phase3: " + timeRegex + "\n" + - gcLogTimeRegex + indent_8 + "Discovered: " + countRegex + "\n" + - gcLogTimeRegex + indent_8 + "Cleared: " + countRegex + "\n"; - String softRefDetailRegex = gcLogTimeRegex + indent_8 + "Phase1: " + timeRegex + "\n" + refDetailRegex; - String enqueueRegex = gcLogTimeRegex + indent_4 + "Reference Enqueuing: " + timeRegex + "\n"; - String enqueueDetailRegex = gcLogTimeRegex + indent_6 + "Reference Counts: Soft: " + countRegex + + String timeRegex = doubleRegex + "ms"; + String totalRegex = gcLogTimeRegex + indent(4) + referenceProcessing + ": " + timeRegex + "\n"; + String balanceRegex = gcLogTimeRegex + indent(8) + "Balance queues: " + timeRegex + "\n"; + String softRefRegex = gcLogTimeRegex + indent(6) + softReference + ": " + timeRegex + "\n"; + String weakRefRegex = gcLogTimeRegex + indent(6) + weakReference + ": " + timeRegex + "\n"; + String finalRefRegex = gcLogTimeRegex + indent(6) + finalReference + ": " + timeRegex + "\n"; + String phantomRefRegex = gcLogTimeRegex + indent(6) + phantomReference + ": " + timeRegex + "\n"; + String refDetailRegex = gcLogTimeRegex + indent(8) + phase2 + ": " + timeRegex + "\n" + + gcLogTimeRegex + indent(8) + phase3 + ": " + timeRegex + "\n" + + gcLogTimeRegex + indent(8) + "Discovered: " + countRegex + "\n" + + gcLogTimeRegex + indent(8) + "Cleared: " + countRegex + "\n"; + String softRefDetailRegex = gcLogTimeRegex + indent(8) + phase1 + ": " + timeRegex + "\n" + refDetailRegex; + String enqueueRegex = gcLogTimeRegex + indent(4) + "Reference Enqueuing: " + timeRegex + "\n"; + String enqueueDetailRegex = gcLogTimeRegex + indent(6) + "Reference Counts: Soft: " + countRegex + " Weak: " + countRegex + " Final: " + countRegex + " Phantom: " + countRegex + "\n"; output.shouldMatch(/* Total Reference processing time */ @@ -83,22 +106,94 @@ public class TestPrintReferences { /* Enqueued Stats */ enqueueDetailRegex ); + } - output.shouldHaveExitValue(0); + // After getting time value, update 'output' for next use. + public static BigDecimal getTimeValue(String name, int indentCount) { + // Pattern of 'name', 'value' and some extra strings. + String patternString = gcLogTimeRegex + indent(indentCount) + name + ": " + "(" + doubleRegex + ")"; + Matcher m = Pattern.compile(patternString).matcher(output); + if (!m.find()) { + throw new RuntimeException("Could not find time log for " + patternString); + } + + String match = m.group(); + String value = m.group(1); + + double result = Double.parseDouble(value); + + int index = output.indexOf(match); + if (index != -1) { + output = output.substring(index, output.length()); + } + + // Convert to BigDecimal to control the precision of floating point arithmetic. + return BigDecimal.valueOf(result); + } + + // Reference log is printing 1 decimal place of elapsed time. + // So sum of each sub-phases could be slightly larger than the enclosing phase in some cases. + // e.g. If there are 3 sub-phases: + // Actual value: SoftReference(5.55) = phase1(1.85) + phase2(1.85) + phase3(1.85) + // Log value: SoftReference(5.6) = phase1(1.9) + phase2(1.9) + phase3(1.9) + // When checked: 5.6 < 5.7 (sum of phase1~3) + public static boolean approximatelyEqual(BigDecimal phaseTime, BigDecimal sumOfSubPhasesTime, BigDecimal tolerance) { + BigDecimal abs = phaseTime.subtract(sumOfSubPhasesTime).abs(); + + int result = abs.compareTo(tolerance); + + // result == -1, abs is less than tolerance. + // result == 0, abs is equal to tolerance. + // result == 1, abs is greater than tolerance. + return (result != 1); + } + + public static BigDecimal checkPhaseTime(String refType) { + BigDecimal phaseTime = getTimeValue(refType, 2); + BigDecimal sumOfSubPhasesTime = BigDecimal.valueOf(0.0); + + if (softReference.equals(refType)) { + sumOfSubPhasesTime = sumOfSubPhasesTime.add(getTimeValue(phase1, 4)); + } + sumOfSubPhasesTime = sumOfSubPhasesTime.add(getTimeValue(phase2, 4)); + sumOfSubPhasesTime = sumOfSubPhasesTime.add(getTimeValue(phase3, 4)); + + // If there are 3 sub-phases, we should allow 0.1 tolerance. + final BigDecimal toleranceFor3SubPhases = BigDecimal.valueOf(0.1); + if (!approximatelyEqual(phaseTime, sumOfSubPhasesTime, toleranceFor3SubPhases)) { + throw new RuntimeException(refType +" time(" + phaseTime + + "ms) is less than the sum(" + sumOfSubPhasesTime + "ms) of each phases"); + } + + return phaseTime; + } + + // Find the first concurrent Reference Processing log and compare phase time vs. sum of sub-phases. + public static void checkLogValue(OutputAnalyzer out) { + output = out.getStdout(); + + BigDecimal refProcTime = getTimeValue(referenceProcessing, 0); + + BigDecimal sumOfSubPhasesTime = checkPhaseTime(softReference); + sumOfSubPhasesTime = sumOfSubPhasesTime.add(checkPhaseTime(weakReference)); + sumOfSubPhasesTime = sumOfSubPhasesTime.add(checkPhaseTime(finalReference)); + sumOfSubPhasesTime = sumOfSubPhasesTime.add(checkPhaseTime(phantomReference)); + + // If there are 4 sub-phases, we should allow 0.2 tolerance. + final BigDecimal toleranceFor4SubPhases = BigDecimal.valueOf(0.2); + if (!approximatelyEqual(refProcTime, sumOfSubPhasesTime, toleranceFor4SubPhases)) { + throw new RuntimeException("Reference Processing time(" + refProcTime + "ms) is less than the sum(" + + sumOfSubPhasesTime + "ms) of each phases"); + } } static class GCTest { - static final int M = 1024 * 1024; + static final int SIZE = 512 * 1024; + static Object[] dummy = new Object[SIZE]; public static void main(String [] args) { - - ArrayList arrSoftRefs = new ArrayList(); - - // Populate to triger GC and then Reference related logs will be printed. - for (int i = 0; i < 10; i++) { - byte[] tmp = new byte[M]; - - arrSoftRefs.add(new SoftReference(tmp)); + for (int i = 0; i < SIZE; i++) { + dummy[i] = new SoftReference<>(new Object()); } } } diff --git a/test/hotspot/jtreg/native_sanity/JniVersion.java b/test/hotspot/jtreg/native_sanity/JniVersion.java index e1451d2e9a5..da9149e99d3 100644 --- a/test/hotspot/jtreg/native_sanity/JniVersion.java +++ b/test/hotspot/jtreg/native_sanity/JniVersion.java @@ -27,12 +27,12 @@ */ public class JniVersion { - public static final int JNI_VERSION_9 = 0x00090000; + public static final int JNI_VERSION_10 = 0x000a0000; public static void main(String... args) throws Exception { System.loadLibrary("JniVersion"); int res = getJniVersion(); - if (res != JNI_VERSION_9) { + if (res != JNI_VERSION_10) { throw new Exception("Unexpected value returned from getJniVersion(): 0x" + Integer.toHexString(res)); } } diff --git a/test/hotspot/jtreg/runtime/BootstrapMethod/BSMCalledTwice.java b/test/hotspot/jtreg/runtime/BootstrapMethod/BSMCalledTwice.java new file mode 100644 index 00000000000..ba9bb957b34 --- /dev/null +++ b/test/hotspot/jtreg/runtime/BootstrapMethod/BSMCalledTwice.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2017, 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. + */ + +/* + * @test + * @bug 8174954 + * @library /test/lib + * @modules java.base/jdk.internal.org.objectweb.asm + * @compile -XDignore.symbol.file BSMCalledTwice.java + * @run main BSMCalledTwice + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.util.*; +import static jdk.internal.org.objectweb.asm.Opcodes.*; +import jdk.internal.org.objectweb.asm.*; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +// BSMCalledTwice generates a class file named "TestC.class" that contains +// bytecodes that represent the following program +// +// public class TestC { +// public static void main(java.lang.String[] arg) { +// for (int i=0; i < 2; i++) { +// try { +// String f = "friend"; +// +// // The "hello " + f in the following statement produces an +// // invokedynamic with a BSM of +// // StringConcatFactory.java/makeConcatWithConstants. +// // The ASM below erroneously puts 2 static arguments, "hello " +// // and "goodbye" on the stack for the BSM. Causing a exception to +// // be thrown when creatingthe CallSite object. +// System.out.println("hello " + f); <--------------- invokedynamic +// +// } catch (Error e) { +// System.out.println("Caught Error:"); +// System.out.println(e.getMessage()); +// e.printStackTrace(); +// } +// } +// } +// } +// +public class BSMCalledTwice implements Opcodes { + static final String classTestCName = "TestC"; + + public static int count_makeSite(String text) { + int count = 0; + String text_ptr = text; + while (text_ptr.indexOf("makeSite") != -1) { + text_ptr = text_ptr.substring(text_ptr.indexOf("makeSite") + 1); + count++; + } + return count; + } + + public static void main(String[] args) throws Exception { + ClassLoader cl = new ClassLoader() { + public Class loadClass(String name) throws ClassNotFoundException { + if (findLoadedClass(name) != null) { + return findLoadedClass(name); + } + + if (classTestCName.equals(name)) { + byte[] classFile = null; + try { + classFile = dumpTestC(); + } catch (Exception e) { + } + return defineClass(classTestCName, classFile, 0, classFile.length); + } + return super.loadClass(name); + } + }; + + cl.loadClass(classTestCName); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, "-cp", ".", classTestCName); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + String test_output = output.getOutput(); + if (test_output == null) { + throw new RuntimeException("Test failed, null test output"); + } + // "makeSite" is currently listed twice in the exception stacks for each + // failing call to the BootstrapMethod. So more that two calls means + // that the BootstrapMethod was called more than once. + int count = count_makeSite(test_output); + if (count < 1 || count > 2) { + throw new RuntimeException("Test failed, bad number of calls to BootstrapMethod"); + } + output.shouldHaveExitValue(0); + } + + public static byte[] dumpTestC () throws Exception { + ClassWriter cw = new ClassWriter(0); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + + cw.visit(53, ACC_PUBLIC + ACC_SUPER, classTestCName, null, "java/lang/Object", null); + + cw.visitInnerClass("java/lang/invoke/MethodHandles$Lookup", + "java/lang/invoke/MethodHandles", "Lookup", + ACC_PUBLIC + ACC_FINAL + ACC_STATIC); + + { + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); + mv.visitCode(); + Label l0 = new Label(); + Label l1 = new Label(); + Label l2 = new Label(); + mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Error"); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 1); + Label l3 = new Label(); + mv.visitLabel(l3); + mv.visitFrame(Opcodes.F_APPEND,1, new Object[] {Opcodes.INTEGER}, 0, null); + mv.visitVarInsn(ILOAD, 1); + mv.visitInsn(ICONST_2); + Label l4 = new Label(); + mv.visitJumpInsn(IF_ICMPGE, l4); + mv.visitLabel(l0); + mv.visitLdcInsn("friend"); + mv.visitVarInsn(ASTORE, 2); + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitVarInsn(ALOAD, 2); + mv.visitInvokeDynamicInsn("makeConcatWithConstants", + "(Ljava/lang/String;)Ljava/lang/String;", + new Handle(Opcodes.H_INVOKESTATIC, + "java/lang/invoke/StringConcatFactory", + "makeConcatWithConstants", + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"), + new Object[]{"hello \u0001", "goodbye"}); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); + mv.visitLabel(l1); + Label l5 = new Label(); + mv.visitJumpInsn(GOTO, l5); + mv.visitLabel(l2); + mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Error"}); + mv.visitVarInsn(ASTORE, 2); + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitLdcInsn("Caught Error:"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Error", "getMessage", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Error", "printStackTrace", "()V", false); + mv.visitLabel(l5); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + mv.visitIincInsn(1, 1); + mv.visitJumpInsn(GOTO, l3); + mv.visitLabel(l4); + mv.visitFrame(Opcodes.F_CHOP,1, null, 0, null); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 3); + mv.visitEnd(); + } + cw.visitEnd(); + + try(FileOutputStream fos = new FileOutputStream(new File("TestC.class"))) { + fos.write(cw.toByteArray()); + } + return cw.toByteArray(); + } +} diff --git a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java index 4e1a6bd9434..ab0b29d95ed 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java +++ b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java @@ -42,10 +42,10 @@ public class VMDeprecatedOptions { // deprecated non-alias flags: {"MaxGCMinorPauseMillis", "1032"}, {"MustCallLoadClassInternal", "false"}, - {"UnsyncloadClass", "false"}, {"MaxRAMFraction", "8"}, {"MinRAMFraction", "2"}, {"InitialRAMFraction", "64"}, + {"AssumeMP", "false"}, // deprecated alias flags (see also aliased_jvm_flags): {"DefaultMaxRAMFraction", "4"}, @@ -75,7 +75,21 @@ public class VMDeprecatedOptions { } } + // Deprecated diagnostic command line options need to be preceded on the + // command line by -XX:+UnlockDiagnosticVMOptions. + static void testDeprecatedDiagnostic(String option, String value) throws Throwable { + String XXoption = CommandLineOptionTest.prepareFlag(option, value); + ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( + CommandLineOptionTest.UNLOCK_DIAGNOSTIC_VM_OPTIONS, XXoption, "-version"); + OutputAnalyzer output = new OutputAnalyzer(processBuilder.start()); + // check for option deprecation message: + output.shouldHaveExitValue(0); + String match = getDeprecationString(option); + output.shouldMatch(match); + } + public static void main(String[] args) throws Throwable { testDeprecated(DEPRECATED_OPTIONS); // Make sure that each deprecated option is mentioned in the output. + testDeprecatedDiagnostic("UnsyncloadClass", "false"); } } diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/common/C.jasm b/test/hotspot/jtreg/runtime/LoaderConstraints/common/C.jasm new file mode 100644 index 00000000000..a7d3f94dffd --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/common/C.jasm @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017, 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. + */ + +// If this file was written in java then some of the tests would fail during +// compilation with errors such as: +// class C inherits unrelated defaults for m() from types I and J +// C is not abstract and does not override abstract method m() in I + +super public class C implements I, J version 52:0 { + + public Method "":"()V" stack 1 locals 1 { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + +} // end Class C diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/common/Foo.java b/test/hotspot/jtreg/runtime/LoaderConstraints/common/Foo.java new file mode 100644 index 00000000000..1a82277ad34 --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/common/Foo.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017, 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. + */ + +public class Foo {} diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/common/J.java b/test/hotspot/jtreg/runtime/LoaderConstraints/common/J.java new file mode 100644 index 00000000000..e9f58ca2777 --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/common/J.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, 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. + */ + +public interface J { + public default Foo m() { return null; } +} diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/common/PreemptingClassLoader.java b/test/hotspot/jtreg/runtime/LoaderConstraints/common/PreemptingClassLoader.java new file mode 100644 index 00000000000..2cc8db0b3ec --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/common/PreemptingClassLoader.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017, 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 java.util.*; +import java.io.*; + +public class PreemptingClassLoader extends ClassLoader { + + private final Set names = new HashSet<>(); + + public PreemptingClassLoader(String... names) { + for (String n : names) this.names.add(n); + } + + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (!names.contains(name)) return super.loadClass(name, resolve); + Class result = findLoadedClass(name); + if (result == null) { + String filename = name.replace('.', '/') + ".class"; + try (InputStream data = getResourceAsStream(filename)) { + if (data == null) throw new ClassNotFoundException(); + try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) { + int b; + do { + b = data.read(); + if (b >= 0) buffer.write(b); + } while (b >= 0); + byte[] bytes = buffer.toByteArray(); + result = defineClass(name, bytes, 0, bytes.length); + } + } catch (IOException e) { + throw new ClassNotFoundException("Error reading class file", e); + } + } + if (resolve) resolveClass(result); + return result; + } + +} diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/itableICCE/I.java b/test/hotspot/jtreg/runtime/LoaderConstraints/itableICCE/I.java new file mode 100644 index 00000000000..25a6c63acfc --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/itableICCE/I.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, 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. + */ + +public interface I { + public default Foo m() { return null; } +} diff --git a/src/hotspot/share/shark/shark_globals.cpp b/test/hotspot/jtreg/runtime/LoaderConstraints/itableICCE/Task.java similarity index 73% rename from src/hotspot/share/shark/shark_globals.cpp rename to test/hotspot/jtreg/runtime/LoaderConstraints/itableICCE/Task.java index b775ac4a474..144d8514010 100644 --- a/src/hotspot/share/shark/shark_globals.cpp +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/itableICCE/Task.java @@ -1,6 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008 Red Hat, Inc. + * Copyright (c) 2017, 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,10 +19,13 @@ * 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 "precompiled.hpp" -#include "shark/shark_globals.hpp" +public class Task implements Runnable { -SHARK_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_NOTPRODUCT_FLAG) + public void run() { + Class c = Foo.class; // forces PreemptingClassLoader to load Foo + C x = new C(); // should not trigger loader constraints exception + x.m(); + } +} diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/itableICCE/Test.java b/test/hotspot/jtreg/runtime/LoaderConstraints/itableICCE/Test.java new file mode 100644 index 00000000000..3cc83b2351b --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/itableICCE/Test.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017, 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. + */ + +/* + * @test + * @bug 8186092 + * @compile ../common/Foo.java + * I.java + * ../common/J.java + * ../common/C.jasm + * Task.java + * ../common/PreemptingClassLoader.java + * @run main/othervm Test + */ + +public class Test { + + // Test that LinkageError exceptions are not thrown during itable creation, + // for loader constraint errors, if the target method is an overpass method. + // + // In this test, during itable creation for class C, method "m()LFoo;" for + // C's super interface I has a different class Foo than the selected method's + // type J. But, the selected method is an overpass method (that throws an + // ICCE). So, no LinkageError exception should be thrown because the loader + // constraint check that would cause the LinkageError should not be done. + public static void main(String... args) throws Exception { + Class c = Foo.class; // forces standard class loader to load Foo + ClassLoader l = new PreemptingClassLoader("Task", "Foo", "C", "I"); + Runnable r = (Runnable) l.loadClass("Task").newInstance(); + try { + r.run(); // Cause an ICCE because both I and J define m()LFoo; + throw new RuntimeException("Expected ICCE exception not thrown"); + } catch (IncompatibleClassChangeError e) { + if (!e.getMessage().contains("Conflicting default methods: I.m J.m")) { + throw new RuntimeException("Wrong ICCE exception thrown: " + e.getMessage()); + } + } + } +} diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/I.java b/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/I.java new file mode 100644 index 00000000000..97fdaa8830b --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/I.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, 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. + */ + +public interface I { + public Foo m(); +} diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Task.java b/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Task.java new file mode 100644 index 00000000000..6d409023eec --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Task.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017, 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. + */ + +public class Task implements Runnable { + + public void run() { + Class c = Foo.class; // forces PreemptingClassLoader to load Foo + C x = new C(); // triggers overloading constraints + x.m(); + } +} diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java b/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java new file mode 100644 index 00000000000..3f2793934c7 --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/itableLdrConstraint/Test.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017, 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. + */ + +/* + * @test + * @bug 8186092 + * @compile ../common/Foo.java + * ../common/J.java + * I.java + * ../common/C.jasm + * Task.java + * ../common/PreemptingClassLoader.java + * @run main/othervm Test + */ + +public class Test { + + // Test that the error message is correct when a loader constraint error is + // detected during itable creation. + // + // In this test, during itable creation for class C, method "m()LFoo;" for + // C's super interface I has a different class Foo than the selected method's + // type super interface J. The selected method is not an overpass method nor + // otherwise excluded from loader constraint checking. So, a LinkageError + // exception should be thrown because the loader constraint check will fail. + public static void main(String... args) throws Exception { + Class c = Foo.class; // forces standard class loader to load Foo + ClassLoader l = new PreemptingClassLoader("Task", "Foo", "C", "I"); + Runnable r = (Runnable) l.loadClass("Task").newInstance(); + try { + r.run(); + throw new RuntimeException("Expected LinkageError exception not thrown"); + } catch (LinkageError e) { + if (!e.getMessage().contains( + "loader constraint violation in interface itable initialization for class C:")) { + throw new RuntimeException("Wrong LinkageError exception thrown: " + e.getMessage()); + } + } + } +} diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/vtableAME/I.java b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableAME/I.java new file mode 100644 index 00000000000..f6e47464837 --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableAME/I.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, 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. + */ + +public interface I extends J { + public Foo m(); +} diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/vtableAME/Task.java b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableAME/Task.java new file mode 100644 index 00000000000..ffc2acd8223 --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableAME/Task.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017, 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. + */ + +public class Task extends C { } diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/vtableAME/Test.java b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableAME/Test.java new file mode 100644 index 00000000000..83a5a7f01e7 --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableAME/Test.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017, 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. + */ + +/* + * @test + * @bug 8186092 + * @compile ../common/Foo.java + * ../common/J.java + * I.java + * ../common/C.jasm + * Task.java + * ../common/PreemptingClassLoader.java + * @run main/othervm Test + */ + +import java.io.PrintStream; +import java.lang.reflect.*; + +public class Test { + + // Test that LinkageError exceptions are not thrown during vtable creation, + // for loader constraint errors, if the target method is an overpass method. + // + // In this test, during vtable creation for class Task, the target method + // "Task.m()LFoo;" is an overpass method (that throws an AME). So, even + // though it is inheriting the method from its super class C, and Task has + // a different class Foo than C, no LinkageError exception should be thrown + // because the loader constraint check that would cause the LinkageError + // should not be done. + public static void main(String args[]) throws Exception { + Class c = Foo.class; // forces standard class loader to load Foo + ClassLoader l = new PreemptingClassLoader("Task", "Foo", "I", "J"); + l.loadClass("Foo"); + l.loadClass("Task").newInstance(); + Task t = new Task(); + try { + t.m(); // Should get AME + throw new RuntimeException("Missing AbstractMethodError exception"); + } catch (AbstractMethodError e) { + if (!e.getMessage().contains("Method Task.m()LFoo; is abstract")) { + throw new RuntimeException("Wrong AME exception thrown: " + e.getMessage()); + } + } + } + +} diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/I.java b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/I.java new file mode 100644 index 00000000000..f6db30fe83b --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/I.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017, 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. + */ + +public interface I extends J { +} diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Task.java b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Task.java new file mode 100644 index 00000000000..d59a7a4fc76 --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Task.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017, 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. + */ + +public class Task extends C { + + public Foo m() { + return null; + } + +} diff --git a/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java new file mode 100644 index 00000000000..e474c1ee16d --- /dev/null +++ b/test/hotspot/jtreg/runtime/LoaderConstraints/vtableLdrConstraint/Test.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017, 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. + */ + +/* + * @test + * @bug 8186092 + * @compile ../common/Foo.java + * ../common/J.java + * I.java + * ../common/C.jasm + * Task.java + * ../common/PreemptingClassLoader.java + * @run main/othervm Test + */ + +public class Test { + + // Test that the error message is correct when a loader constraint error is + // detected during vtable creation. + // + // In this test, during vtable creation for class Task, method "Task.m()LFoo;" + // overrides "J.m()LFoo;". But, Task's class Foo and super type J's class Foo + // are different. So, a LinkageError exception should be thrown because the + // loader constraint check will fail. + public static void main(String args[]) throws Exception { + Class c = Foo.class; // forces standard class loader to load Foo + ClassLoader l = new PreemptingClassLoader("Task", "Foo", "I"); + l.loadClass("Foo"); + try { + l.loadClass("Task").newInstance(); + throw new RuntimeException("Expected LinkageError exception not thrown"); + } catch (LinkageError e) { + if (!e.getMessage().contains( + "loader constraint violation for class Task: when selecting overriding method") || + !e.getMessage().contains( + "for its super type J have different Class objects for the type Foo")) { + throw new RuntimeException("Wrong LinkageError exception thrown: " + e.getMessage()); + } + } + } + +} + diff --git a/test/hotspot/jtreg/runtime/Metaspace/MaxMetaspaceSizeTest.java b/test/hotspot/jtreg/runtime/Metaspace/MaxMetaspaceSizeTest.java new file mode 100644 index 00000000000..f50477caa2a --- /dev/null +++ b/test/hotspot/jtreg/runtime/Metaspace/MaxMetaspaceSizeTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017, 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 jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +/* + * @test MaxMetaspaceSizeTest + * @requires vm.bits == "64" + * @bug 8087291 + * @library /test/lib + * @run main/othervm MaxMetaspaceSizeTest + */ + +public class MaxMetaspaceSizeTest { + public static void main(String... args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xmx1g", + "-XX:InitialBootClassLoaderMetaspaceSize=4195328", + "-XX:MaxMetaspaceSize=4195328", + "-XX:+UseCompressedClassPointers", + "-XX:CompressedClassSpaceSize=1g", + "--version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("MaxMetaspaceSize is too small."); + } +} diff --git a/test/hotspot/jtreg/runtime/RedefineTests/RedefineDoubleDelete.java b/test/hotspot/jtreg/runtime/RedefineTests/RedefineDoubleDelete.java new file mode 100644 index 00000000000..a158771d63b --- /dev/null +++ b/test/hotspot/jtreg/runtime/RedefineTests/RedefineDoubleDelete.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2017, 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. + */ + +/* + * @test + * @bug 8178870 + * @summary Redefine class with CFLH twice to test deleting the cached_class_file + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @modules java.compiler + * java.instrument + * jdk.jartool/sun.tools.jar + * @run main RedefineClassHelper + * @run main/othervm/native -Xlog:redefine+class+load+exceptions -agentlib:RedefineDoubleDelete -javaagent:redefineagent.jar RedefineDoubleDelete + */ + +public class RedefineDoubleDelete { + + // Class gets a redefinition error because it adds a data member + public static String newB = + "class RedefineDoubleDelete$B {" + + " int count1 = 0;" + + "}"; + + public static String newerB = + "class RedefineDoubleDelete$B { " + + " int faa() { System.out.println(\"baa\"); return 2; }" + + "}"; + + // The ClassFileLoadHook for this class turns foo into faa and prints out faa. + static class B { + int faa() { System.out.println("foo"); return 1; } + } + + public static void main(String args[]) throws Exception { + + B b = new B(); + int val = b.faa(); + if (val != 1) { + throw new RuntimeException("return value wrong " + val); + } + + // Redefine B twice to get cached_class_file in both B scratch classes + try { + RedefineClassHelper.redefineClass(B.class, newB); + } catch (java.lang.UnsupportedOperationException e) { + // this is expected + } + try { + RedefineClassHelper.redefineClass(B.class, newB); + } catch (java.lang.UnsupportedOperationException e) { + // this is expected + } + + // Do a full GC. + System.gc(); + + // Redefine with a compatible class + RedefineClassHelper.redefineClass(B.class, newerB); + val = b.faa(); + if (val != 2) { + throw new RuntimeException("return value wrong " + val); + } + + // Do another full GC to clean things up. + System.gc(); + } +} diff --git a/test/hotspot/jtreg/runtime/RedefineTests/libRedefineDoubleDelete.c b/test/hotspot/jtreg/runtime/RedefineTests/libRedefineDoubleDelete.c new file mode 100644 index 00000000000..b5d0dc0afe6 --- /dev/null +++ b/test/hotspot/jtreg/runtime/RedefineTests/libRedefineDoubleDelete.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2017, 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 "jvmti.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef JNI_ENV_ARG + +#ifdef __cplusplus +#define JNI_ENV_ARG(x, y) y +#define JNI_ENV_PTR(x) x +#else +#define JNI_ENV_ARG(x,y) x, y +#define JNI_ENV_PTR(x) (*x) +#endif + +#endif + +#define TranslateError(err) "JVMTI error" + +static jvmtiEnv *jvmti = NULL; + +static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); + +JNIEXPORT +jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} + +JNIEXPORT +jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} + +JNIEXPORT +jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { + return JNI_VERSION_9; +} + + +static jint newClassDataLen = 0; +static unsigned char* newClassData = NULL; + +static jint +getBytecodes(jvmtiEnv *jvmti_env, + jint class_data_len, const unsigned char* class_data) { + int i; + jint res; + + newClassDataLen = class_data_len; + res = (*jvmti_env)->Allocate(jvmti_env, newClassDataLen, &newClassData); + if (res != JNI_OK) { + printf(" Unable to allocate bytes\n"); + return JNI_ERR; + } + for (i = 0; i < newClassDataLen; i++) { + newClassData[i] = class_data[i]; + // Rewrite oo in class to aa + if (i > 0 && class_data[i] == 'o' && class_data[i-1] == 'o') { + newClassData[i] = newClassData[i-1] = 'a'; + } + } + printf(" ... copied bytecode: %d bytes\n", (int)newClassDataLen); + return JNI_OK; +} + + +static void JNICALL +Callback_ClassFileLoadHook(jvmtiEnv *jvmti_env, JNIEnv *env, + jclass class_being_redefined, + jobject loader, const char* name, jobject protection_domain, + jint class_data_len, const unsigned char* class_data, + jint *new_class_data_len, unsigned char** new_class_data) { + if (name != NULL && strcmp(name, "RedefineDoubleDelete$B") == 0) { + if (newClassData == NULL) { + jint res = getBytecodes(jvmti_env, class_data_len, class_data); + if (res == JNI_ERR) { + printf(">>> ClassFileLoadHook event: class name %s FAILED\n", name); + return; + } + // Only change for first CFLH event. + *new_class_data_len = newClassDataLen; + *new_class_data = newClassData; + } + printf(">>> ClassFileLoadHook event: class name %s\n", name); + } +} + +static +jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { + jint res, size; + jvmtiCapabilities caps; + jvmtiEventCallbacks callbacks; + jvmtiError err; + + res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), + JVMTI_VERSION_9); + if (res != JNI_OK || jvmti == NULL) { + printf(" Error: wrong result of a valid call to GetEnv!\n"); + return JNI_ERR; + } + + printf("Enabling following capabilities: can_generate_all_class_hook_events, " + "can_retransform_classes, can_redefine_classes"); + memset(&caps, 0, sizeof(caps)); + caps.can_generate_all_class_hook_events = 1; + caps.can_retransform_classes = 1; + caps.can_redefine_classes = 1; + printf("\n"); + + err = (*jvmti)->AddCapabilities(jvmti, &caps); + if (err != JVMTI_ERROR_NONE) { + printf(" Error in AddCapabilites: %s (%d)\n", TranslateError(err), err); + return JNI_ERR; + } + + size = (jint)sizeof(callbacks); + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.ClassFileLoadHook = Callback_ClassFileLoadHook; + + err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, size); + if (err != JVMTI_ERROR_NONE) { + printf(" Error in SetEventCallbacks: %s (%d)\n", TranslateError(err), err); + return JNI_ERR; + } + + err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); + if (err != JVMTI_ERROR_NONE) { + printf(" Error in SetEventNotificationMode: %s (%d)\n", TranslateError(err), err); + return JNI_ERR; + } + + return JNI_OK; +} + +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/runtime/SharedArchiveFile/MaxMetaspaceSize.java b/test/hotspot/jtreg/runtime/SharedArchiveFile/MaxMetaspaceSize.java index 3e9139b8513..f8799b3843d 100644 --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/MaxMetaspaceSize.java +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/MaxMetaspaceSize.java @@ -31,14 +31,27 @@ * java.management */ +import java.util.ArrayList; + import jdk.test.lib.cds.CDSTestUtils; import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Platform; public class MaxMetaspaceSize { public static void main(String[] args) throws Exception { + ArrayList processArgs = new ArrayList<>(); + processArgs.add("-Xshare:dump"); + + if (Platform.is64bit()) { + processArgs.add("-XX:MaxMetaspaceSize=3m"); + processArgs.add("-XX:CompressedClassSpaceSize=1m"); + processArgs.add("-XX:InitialBootClassLoaderMetaspaceSize=1m"); + } else { + processArgs.add("-XX:MaxMetaspaceSize=1m"); + } + String msg = "OutOfMemoryError: Metaspace"; - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:MaxMetaspaceSize=1m", "-Xshare:dump"); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(processArgs.toArray(new String[0])); CDSTestUtils.executeAndLog(pb, "dump").shouldContain(msg).shouldHaveExitValue(1); } } diff --git a/test/hotspot/jtreg/runtime/SharedArchiveFile/SpaceUtilizationCheck.java b/test/hotspot/jtreg/runtime/SharedArchiveFile/SpaceUtilizationCheck.java index f2e0f6964ca..f9cfe9f3ae4 100644 --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/SpaceUtilizationCheck.java +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/SpaceUtilizationCheck.java @@ -64,7 +64,7 @@ public class SpaceUtilizationCheck { static void test(String... extra_options) throws Exception { OutputAnalyzer output = CDSTestUtils.createArchive(extra_options); CDSTestUtils.checkDump(output); - Pattern pattern = Pattern.compile("^(..) space: *([0-9]+).* out of *([0-9]+) bytes .* at 0x([0-9a0-f]+)"); + Pattern pattern = Pattern.compile("^(..) *space: *([0-9]+).* out of *([0-9]+) bytes .* at 0x([0-9a0-f]+)"); WhiteBox wb = WhiteBox.getWhiteBox(); long reserve_alignment = wb.metaspaceReserveAlignment(); System.out.println("Metaspace::reserve_alignment() = " + reserve_alignment); diff --git a/test/hotspot/jtreg/runtime/containers/docker/DockerBasicTest.java b/test/hotspot/jtreg/runtime/containers/docker/DockerBasicTest.java new file mode 100644 index 00000000000..41867e74b89 --- /dev/null +++ b/test/hotspot/jtreg/runtime/containers/docker/DockerBasicTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017, 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. + */ + + +/* + * @test + * @summary Basic (sanity) test for JDK-under-test inside a docker image. + * @requires (docker.support) + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * jdk.jartool/sun.tools.jar + * @build HelloDocker + * @run driver DockerBasicTest + */ +import jdk.test.lib.containers.docker.DockerRunOptions; +import jdk.test.lib.containers.docker.DockerTestUtils; +import jdk.test.lib.Platform; +import jdk.test.lib.Utils; + + +public class DockerBasicTest { + private static final String imageNameAndTag = "jdk10-internal:test"; + // Diganostics: set to false to examine image after the test + private static final boolean removeImageAfterTest = true; + + public static void main(String[] args) throws Exception { + if (!DockerTestUtils.canTestDocker()) { + return; + } + + DockerTestUtils.buildJdkDockerImage(imageNameAndTag, "Dockerfile-BasicTest", "jdk-docker"); + + try { + testJavaVersion(); + testHelloDocker(); + } finally { + if (removeImageAfterTest) + DockerTestUtils.removeDockerImage(imageNameAndTag); + } + } + + + private static void testJavaVersion() throws Exception { + DockerTestUtils.dockerRunJava( + new DockerRunOptions(imageNameAndTag, "/jdk/bin/java", "-version")) + .shouldHaveExitValue(0) + .shouldContain(Platform.vmName); + } + + + private static void testHelloDocker() throws Exception { + DockerRunOptions opts = + new DockerRunOptions(imageNameAndTag, "/jdk/bin/java", "HelloDocker") + .addJavaOpts("-cp", "/test-classes/") + .addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/"); + + DockerTestUtils.dockerRunJava(opts) + .shouldHaveExitValue(0) + .shouldContain("Hello Docker"); + } + +} diff --git a/test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest b/test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest new file mode 100644 index 00000000000..166c969289e --- /dev/null +++ b/test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest @@ -0,0 +1,8 @@ +FROM oraclelinux:7.2 +MAINTAINER mikhailo.seledtsov@oracle.com + +COPY /jdk /jdk + +ENV JAVA_HOME=/jdk + +CMD ["/bin/bash"] diff --git a/test/hotspot/jtreg/runtime/containers/docker/HelloDocker.java b/test/hotspot/jtreg/runtime/containers/docker/HelloDocker.java new file mode 100644 index 00000000000..9b5f56035b3 --- /dev/null +++ b/test/hotspot/jtreg/runtime/containers/docker/HelloDocker.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017, 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. + */ + +public class HelloDocker { + public static void main(String args[]) { + System.out.println("Hello Docker"); + } +} diff --git a/test/hotspot/jtreg/runtime/getSysPackage/GetPackageXbootclasspath.java b/test/hotspot/jtreg/runtime/getSysPackage/GetPackageXbootclasspath.java new file mode 100644 index 00000000000..5884adfc524 --- /dev/null +++ b/test/hotspot/jtreg/runtime/getSysPackage/GetPackageXbootclasspath.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017, 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. + */ + +/* + * @test + * @bug 8187436 + * @summary Test that getPackage() works with a class loaded via -Xbootclasspath/a. + * @library /test/lib + * @run main/othervm GetPackageXbootclasspath + */ + +// This is a regression test for a bug with the exploded build but should pass +// when run with either the normal or exploded build. +import jdk.test.lib.compiler.InMemoryJavaCompiler; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class GetPackageXbootclasspath { + + public static void main(String args[]) throws Exception { + + String Test_src = + "package P; " + + "public class Test { " + + "public static void main(String[] args) throws Exception { " + + "Package p = Test.class.getPackage(); " + + "System.out.println(\"Test Passed\"); " + + "} " + + "}"; + + String test_classes = System.getProperty("test.classes"); + ClassFileInstaller.writeClassToDisk("P/Test", + InMemoryJavaCompiler.compile("P.Test", Test_src), test_classes); + + new OutputAnalyzer(ProcessTools.createJavaProcessBuilder( + "-Xbootclasspath/a:" + test_classes, "P.Test") + .start()).shouldContain("Test Passed"); + } +} diff --git a/test/hotspot/jtreg/runtime/getSysPackage/GetSysPkgTest.java b/test/hotspot/jtreg/runtime/getSysPackage/GetSysPkgTest.java index 75360e2e394..9e4dbedbe23 100644 --- a/test/hotspot/jtreg/runtime/getSysPackage/GetSysPkgTest.java +++ b/test/hotspot/jtreg/runtime/getSysPackage/GetSysPkgTest.java @@ -25,7 +25,7 @@ * @test * @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.loader - * java.desktop + * java.logging * @library /test/lib * @run main/othervm GetSysPkgTest */ @@ -134,10 +134,11 @@ public class GetSysPkgTest { getPkg("GetSysPkg_package", null); // Access a class with a package in a boot loader module other than java.base - clss = Class.forName("java.awt.Button"); + clss = Class.forName("java.util.logging.Level"); + if (clss == null) - throw new RuntimeException("Could not find class java.awt.Button"); - getPkg("java/awt", "jrt:/java.desktop"); + throw new RuntimeException("Could not find class java.util.logging.Level"); + getPkg("java/util/logging", "jrt:/java.logging"); // Test getting the package location from a class found via -Xbootclasspath/a clss = Class.forName("BootLdr_package.BootLdrPkg"); diff --git a/test/hotspot/jtreg/runtime/jni/FindClass/BootLoaderTest.java b/test/hotspot/jtreg/runtime/jni/FindClass/BootLoaderTest.java new file mode 100644 index 00000000000..daad132424d --- /dev/null +++ b/test/hotspot/jtreg/runtime/jni/FindClass/BootLoaderTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017, 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 java.lang.BootNativeLibrary; + +/* + * This is called from FindClassFromBoot class. + */ +public class BootLoaderTest { + public static void main(String... args) throws Exception { + testJNIFindClass("java/lang/String", String.class); + testJNIFindClass("java/lang/BootNativeLibrary", BootNativeLibrary.class); + testJNIFindClass("BootLoaderTest", null); + } + + /* + * Call JNI FindClass with null loader as the context + */ + static void testJNIFindClass(String name, Class expected) { + Class c = BootNativeLibrary.findClass(name); + if (c != expected) { + throw new RuntimeException("FindClass " + c + " expected: " + expected); + } + } +} diff --git a/test/hotspot/jtreg/runtime/jni/FindClass/FindClassFromBoot.java b/test/hotspot/jtreg/runtime/jni/FindClass/FindClassFromBoot.java new file mode 100644 index 00000000000..06db9c07c73 --- /dev/null +++ b/test/hotspot/jtreg/runtime/jni/FindClass/FindClassFromBoot.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017, 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. + */ + +/* + * @test + * @bug 8189193 + * @library /test/lib + * @build jdk.test.lib.process.ProcessTools + * @build java.base/java.lang.BootNativeLibrary BootLoaderTest FindClassFromBoot + * @run main/othervm/native -Xcheck:jni FindClassFromBoot + * @summary verify if the native library loaded by the boot loader + * can only find classes visible to the boot loader + */ + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import jdk.test.lib.process.ProcessTools; + +public class FindClassFromBoot { + public static void main(String... args) throws Exception { + Path patches = Paths.get(System.getProperty("test.classes"), "patches", "java.base"); + String syspaths = System.getProperty("sun.boot.library.path") + + File.pathSeparator + System.getProperty("java.library.path"); + ProcessTools.executeTestJvm("-Dsun.boot.library.path=" + syspaths, + "--patch-module", "java.base=" + patches.toString(), + "BootLoaderTest") + .shouldHaveExitValue(0); + } +} diff --git a/test/hotspot/jtreg/runtime/jni/FindClass/java.base/java/lang/BootNativeLibrary.java b/test/hotspot/jtreg/runtime/jni/FindClass/java.base/java/lang/BootNativeLibrary.java new file mode 100644 index 00000000000..677c24b1f6a --- /dev/null +++ b/test/hotspot/jtreg/runtime/jni/FindClass/java.base/java/lang/BootNativeLibrary.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017, 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 java.lang; + +public class BootNativeLibrary { + static { + System.loadLibrary("bootLoaderTest"); + } + + public static native Class findClass(String name); +} diff --git a/test/hotspot/jtreg/runtime/jni/FindClass/libbootLoaderTest.c b/test/hotspot/jtreg/runtime/jni/FindClass/libbootLoaderTest.c new file mode 100644 index 00000000000..baeba46d5cf --- /dev/null +++ b/test/hotspot/jtreg/runtime/jni/FindClass/libbootLoaderTest.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017, 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 "jni.h" +#include "jni_util.h" + +JNIEXPORT jclass JNICALL +Java_java_lang_BootNativeLibrary_findClass +(JNIEnv *env, jclass cls, jstring name) { + jclass ncdfe; + jthrowable t; + + const char* classname = (*env)->GetStringUTFChars(env, name, JNI_FALSE); + jclass c = (*env)->FindClass(env, classname); + (*env)->ReleaseStringUTFChars(env, name, classname); + + if (c == NULL) { + // clear NCDFE + t = (*env)->ExceptionOccurred(env); + ncdfe = (*env)->FindClass(env, "java/lang/NoClassDefFoundError"); + if (t != NULL && (*env)->IsInstanceOf(env, t, ncdfe)) { + (*env)->ExceptionClear(env); + } + } + return c; +} diff --git a/test/hotspot/jtreg/runtime/modules/AccessCheck/MethodAccessReadTwice.java b/test/hotspot/jtreg/runtime/modules/AccessCheck/MethodAccessReadTwice.java new file mode 100644 index 00000000000..29bbe7f39b0 --- /dev/null +++ b/test/hotspot/jtreg/runtime/modules/AccessCheck/MethodAccessReadTwice.java @@ -0,0 +1,167 @@ +/* + Copyright (c) 2017, 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. + */ + +/* + * @test + * @bug 8174954 + * @summary Test that invokedynamic instructions, that initially throw IAE exceptions + * because of a missing module read edge, behave correctly when executed + * after the module read edge is added. + * @compile ModuleLibrary.java + * p2/c2.java + * p5/c5.java + * p7/c7.java + * @run main/othervm MethodAccessReadTwice + */ + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.ModuleLayer; +import java.lang.Module; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +// defines first_mod --> packages p5 +// defines second_mod --> package p2, p2 is exported to first_mod +// defines third_mod --> packages p7 + +public class MethodAccessReadTwice { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publicly defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: first_mod + // Can read: java.base + // Packages: p5 + // Packages exported: p5 is exported unqualifiedly + ModuleDescriptor descriptor_first_mod = + ModuleDescriptor.newModule("first_mod") + .requires("java.base") + .exports("p5") + .build(); + + // Define module: second_mod + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported to first_mod + ModuleDescriptor descriptor_second_mod = + ModuleDescriptor.newModule("second_mod") + .requires("java.base") + .exports("p2") + .build(); + + // Define module: third_mod + // Can read: java.base + // Packages: p7 + // Packages exported: p7 is exported unqualifiedly + ModuleDescriptor descriptor_third_mod = + ModuleDescriptor.newModule("third_mod") + .requires("java.base") + .exports("p7") + .build(); + + // Set up a ModuleFinder containing all modules for this layer + ModuleFinder finder = ModuleLibrary.of(descriptor_first_mod, + descriptor_second_mod, + descriptor_third_mod); + + // Resolves "first_mod", "second_mod", and "third_mod" + Configuration cf = ModuleLayer.boot() + .configuration() + .resolve(finder, ModuleFinder.of(), + Set.of("first_mod", "second_mod", "third_mod")); + + // Map each module to this class loader + Map map = new HashMap<>(); + ClassLoader loader = MethodAccessReadTwice.class.getClassLoader(); + map.put("first_mod", loader); + map.put("second_mod", loader); + map.put("third_mod", loader); + + // Create Layer that contains first_mod, second_mod, and third_mod + ModuleLayer layer = ModuleLayer.boot().defineModules(cf, map::get); + + Class p2_c2_class = loader.loadClass("p2.c2"); + Class p5_c5_class = loader.loadClass("p5.c5"); + Class p7_c7_class = loader.loadClass("p7.c7"); + + Module first_mod = p5_c5_class.getModule(); + Module second_mod = p2_c2_class.getModule(); + Module third_mod = p7_c7_class.getModule(); + + p5.c5 c5_obj = new p5.c5(); + p2.c2 c2_obj = new p2.c2(); + p7.c7 c7_obj = new p7.c7(); + + // Test that if an invokedynamic instruction gets an IAE exception because + // of a module read issue, and then the read issue is fixed, that + // re-executing the same invokedynamic instruction will get the same IAE. + + // First access check for p5.c5 --> call to method5 --> tries to access p2.c2 + try { + // Should throw IAE because p5.c5's module cannot read p2.c2's module. + c5_obj.method5(c2_obj); + throw new RuntimeException("Test Failed, module first_mod should not have access to p2.c2"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module first_mod does not read module second_mod"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #1"); + } + } + + // Add a read edge from p5/c5's module (first_mod) to p2.c2's module (second_mod) + c5_obj.methodAddReadEdge(p2_c2_class.getModule()); + // Second access check for p5.c5, should have same result as first + try { + c5_obj.method5(c2_obj); // should result in IAE + throw new RuntimeException("Test Failed, access should have been cached above"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module first_mod does not read module second_mod"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #2"); + } + } + + + // Test that if one invokedynamic instruction gets an IAE exception + // because of a module read issue, and then the read issue is fixed, that + // a subsequent invokedynamic instruction, that tries the same access, + // succeeds. + c7_obj.method7(c2_obj, second_mod); // Should not result in IAE + } + + public static void main(String args[]) throws Throwable { + MethodAccessReadTwice test = new MethodAccessReadTwice(); + test.createLayerOnBoot(); + } +} diff --git a/test/hotspot/jtreg/runtime/modules/AccessCheck/p5/c5.java b/test/hotspot/jtreg/runtime/modules/AccessCheck/p5/c5.java new file mode 100644 index 00000000000..a6d0c1bbe2f --- /dev/null +++ b/test/hotspot/jtreg/runtime/modules/AccessCheck/p5/c5.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017, 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 p5; + +import java.lang.Module; +import p2.c2; + +public class c5 { + public void method5(p2.c2 param) { + // The invokedynamic opcode that gets generated for the '+' string + // concatenation operator throws an IllegalAccessError when trying to + // access 'param'. + System.out.println("In c5's method5 with param = " + param); + } + + public void methodAddReadEdge(Module m) { + // Add a read edge from p5/c5's module (first_mod) to second_mod + c5.class.getModule().addReads(m); + } +} diff --git a/test/hotspot/jtreg/runtime/modules/AccessCheck/p7/c7.java b/test/hotspot/jtreg/runtime/modules/AccessCheck/p7/c7.java new file mode 100644 index 00000000000..9aa378cb8fa --- /dev/null +++ b/test/hotspot/jtreg/runtime/modules/AccessCheck/p7/c7.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017, 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 p7; + +import java.lang.Module; +import p2.c2; + +public class c7 { + public void method7(p2.c2 param, Module c2Mod) { + try { + // The invokedynamic opcode that gets generated for the '+' string + // concatenation operator throws an IllegalAccessError when trying + // to access 'param'. + System.out.println("In c7's method7 with param = " + param); + throw new java.lang.RuntimeException("c7 failed to throw expected IllegalAccessError"); + } catch (IllegalAccessError e) { + } + methodAddReadEdge(c2Mod); + + // This invokedynamic (for the string concat) should succeed because of + // the added read edge. The fact that the invokedynamic executed before + // the read edge was added threw an IllegalAccessError exception should + // not affect this one. + try { + System.out.println("In c7's method7 with param = " + param); + } catch (IllegalAccessError e) { + throw new java.lang.RuntimeException("Unexpected IllegalAccessError: " + e.getMessage()); + } + } + + public void methodAddReadEdge(Module m) { + // Add a read edge from p7/c7's module (third_mod) to module m. + c7.class.getModule().addReads(m); + } +} + diff --git a/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleCDS.java b/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleCDS.java index 8321eb6ddb2..6b5d3c7e37c 100644 --- a/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleCDS.java +++ b/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleCDS.java @@ -50,7 +50,7 @@ public class PatchModuleCDS { "-Xlog:class+path=info", "-version"); new OutputAnalyzer(pb.start()) - .shouldContain("ro space:"); // Make sure archive got created. + .shouldContain("ro space:"); // Make sure archive got created. // Case 2: Test that directory in --patch-module is supported for CDS dumping // Create a class file in the module java.base. @@ -73,7 +73,7 @@ public class PatchModuleCDS { "-Xlog:class+path=info", "-version"); new OutputAnalyzer(pb.start()) - .shouldContain("ro space:"); // Make sure archive got created. + .shouldContain("ro space:"); // Make sure archive got created. // Case 3a: Test CDS dumping with jar file in --patch-module BasicJarBuilder.build("javanaming", "javax/naming/spi/NamingManager"); @@ -87,7 +87,7 @@ public class PatchModuleCDS { "-Xlog:class+path=info", "PatchModuleMain", "javax.naming.spi.NamingManager"); new OutputAnalyzer(pb.start()) - .shouldContain("ro space:"); // Make sure archive got created. + .shouldContain("ro space:"); // Make sure archive got created. // Case 3b: Test CDS run with jar file in --patch-module pb = ProcessTools.createJavaProcessBuilder( diff --git a/test/hotspot/jtreg/serviceability/jvmti/ModuleAwareAgents/ClassFileLoadHook/libMAAClassFileLoadHook.c b/test/hotspot/jtreg/serviceability/jvmti/ModuleAwareAgents/ClassFileLoadHook/libMAAClassFileLoadHook.c index 04ecb68867d..576c5bfa4fe 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/ModuleAwareAgents/ClassFileLoadHook/libMAAClassFileLoadHook.c +++ b/test/hotspot/jtreg/serviceability/jvmti/ModuleAwareAgents/ClassFileLoadHook/libMAAClassFileLoadHook.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -137,6 +137,7 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { jvmtiEventCallbacks callbacks; jvmtiError err; + printf("agent options: %s\n", options); if (options != NULL) { if (strstr(options, "with_early_vmstart") != NULL) { with_early_vm_start_capability = JNI_TRUE; @@ -205,9 +206,9 @@ Java_MAAClassFileLoadHook_check(JNIEnv *env, jclass cls) { } /* - * Expecting that we always get ClassFileLoadHook events in the VM Start phase. + * Expecting ClassFileLoadHook events in the VM Start phase if early_vm_start is enabled. */ - if (cflh_events_vm_start_count == 0) { + if (with_early_vm_start_capability == JNI_TRUE && cflh_events_vm_start_count == 0) { throw_exc(env, "Didn't get ClassFileLoadHook events in start phase!\n"); return FAILED; } diff --git a/test/hotspot/jtreg/serviceability/sa/TestInstanceKlassSize.java b/test/hotspot/jtreg/serviceability/sa/TestInstanceKlassSize.java index 9890b3d6739..adae00d9904 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestInstanceKlassSize.java +++ b/test/hotspot/jtreg/serviceability/sa/TestInstanceKlassSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -102,7 +102,6 @@ public class TestInstanceKlassSize { String[] instanceKlassNames = new String[] { " java.lang.Object", " java.util.Vector", - " sun.util.PreHashedMap", " java.lang.String", " java.lang.Thread", " java.lang.Byte", @@ -166,7 +165,7 @@ public class TestInstanceKlassSize { InstanceKlass ik = SystemDictionaryHelper.findInstanceKlass( SAInstanceKlassName); Asserts.assertNotNull(ik, - String.format("Unable to find instance klass for %s", ik)); + String.format("Unable to find instance klass for %s", SAInstanceKlassName)); System.out.println("SA: The size of " + SAInstanceKlassName + " is " + ik.getSize()); } @@ -187,7 +186,6 @@ public class TestInstanceKlassSize { String[] SAInstanceKlassNames = new String[] { "java.lang.Object", "java.util.Vector", - "sun.util.PreHashedMap", "java.lang.String", "java.lang.Thread", "java.lang.Byte" diff --git a/test/hotspot/jtreg/serviceability/sa/TestRevPtrsForInvokeDynamic.java b/test/hotspot/jtreg/serviceability/sa/TestRevPtrsForInvokeDynamic.java new file mode 100644 index 00000000000..4936e90cd31 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/sa/TestRevPtrsForInvokeDynamic.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017, 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 java.util.ArrayList; +import java.util.List; + +import sun.jvm.hotspot.HotSpotAgent; +import sun.jvm.hotspot.utilities.ReversePtrsAnalysis; + +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.Asserts; +import jdk.test.lib.JDKToolFinder; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Utils; + +/* + * @test + * @library /test/lib + * @requires os.family != "mac" + * @modules java.base/jdk.internal.misc + * jdk.hotspot.agent/sun.jvm.hotspot + * jdk.hotspot.agent/sun.jvm.hotspot.utilities + * @run main/othervm TestRevPtrsForInvokeDynamic + */ + +public class TestRevPtrsForInvokeDynamic { + + private static LingeredAppWithInvokeDynamic theApp = null; + + private static void computeReversePointers(String pid) throws Exception { + HotSpotAgent agent = new HotSpotAgent(); + + try { + agent.attach(Integer.parseInt(pid)); + ReversePtrsAnalysis analysis = new ReversePtrsAnalysis(); + analysis.run(); + } finally { + agent.detach(); + } + } + + private static void createAnotherToAttach(long lingeredAppPid) + throws Exception { + String[] toolArgs = { + "--add-modules=jdk.hotspot.agent", + "--add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED", + "--add-exports=jdk.hotspot.agent/sun.jvm.hotspot.utilities=ALL-UNNAMED", + "TestRevPtrsForInvokeDynamic", + Long.toString(lingeredAppPid) + }; + + // Start a new process to attach to the lingered app + ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(toolArgs); + OutputAnalyzer SAOutput = ProcessTools.executeProcess(processBuilder); + SAOutput.shouldHaveExitValue(0); + System.out.println(SAOutput.getOutput()); + } + + public static void main (String... args) throws Exception { + if (!Platform.shouldSAAttach()) { + System.out.println( + "SA attach not expected to work - test skipped."); + return; + } + + if (args == null || args.length == 0) { + try { + List vmArgs = new ArrayList(); + vmArgs.add("-XX:+UsePerfData"); + vmArgs.addAll(Utils.getVmOptions()); + + theApp = new LingeredAppWithInvokeDynamic(); + LingeredApp.startApp(vmArgs, theApp); + createAnotherToAttach(theApp.getPid()); + } finally { + LingeredApp.stopApp(theApp); + } + } else { + computeReversePointers(args[0]); + } + } +} diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 7311f54e28b..46a8037349c 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -304,14 +304,6 @@ sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java 8057732 generic- com/sun/tools/attach/StartManagementAgent.java 8179700 generic-all -sun/tools/jhsdb/AlternateHashingTest.java 8184042 macosx-all - -sun/tools/jhsdb/BasicLauncherTest.java 8184042 macosx-all - -sun/tools/jhsdb/HeapDumpTest.java 8184042 macosx-all - -sun/tools/jhsdb/heapconfig/JMapHeapConfigTest.java 8184042 macosx-all - ############################################################################ # jdk_other diff --git a/test/jdk/java/lang/management/ThreadMXBean/MaxDepthForThreadInfoTest.java b/test/jdk/java/lang/management/ThreadMXBean/MaxDepthForThreadInfoTest.java new file mode 100644 index 00000000000..67a8a53913b --- /dev/null +++ b/test/jdk/java/lang/management/ThreadMXBean/MaxDepthForThreadInfoTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017, 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. + */ + +/* + * @test + * @bug 8185003 + * @build ThreadDump + * @run main MaxDepthForThreadInfoTest + * @summary verifies the functionality of ThreadMXBean.dumpAllThreads + * and ThreadMXBean.getThreadInfo with maxDepth argument + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; + + + +public class MaxDepthForThreadInfoTest { + + + public static void main(String[] Args) { + + ThreadMXBean tmxb = ManagementFactory.getThreadMXBean(); + + long[] threadIds = tmxb.getAllThreadIds(); + + ThreadInfo[] tinfos = tmxb.getThreadInfo(threadIds, true, true, 0); + for (ThreadInfo ti : tinfos) { + if (ti.getStackTrace().length > 0) { + ThreadDump.printThreadInfo(ti); + throw new RuntimeException("more than requested " + + "number of frames dumped"); + } + } + + tinfos = tmxb.getThreadInfo(threadIds, true, true, 3); + for (ThreadInfo ti : tinfos) { + if (ti.getStackTrace().length > 3) { + ThreadDump.printThreadInfo(ti); + throw new RuntimeException("more than requested " + + "number of frames dumped"); + } + } + + try { + tmxb.getThreadInfo(threadIds, true, true, -1); + throw new RuntimeException("Didn't throw IllegalArgumentException " + + "for negative maxdepth value"); + } catch (IllegalArgumentException e) { + System.out.println("Throwed IllegalArgumentException as expected"); + } + + tinfos = tmxb.dumpAllThreads(true, true, 0); + for (ThreadInfo ti : tinfos) { + if (ti.getStackTrace().length > 0) { + ThreadDump.printThreadInfo(ti); + throw new RuntimeException("more than requested " + + "number of frames dumped"); + } + } + tinfos = tmxb.dumpAllThreads(true, true, 2); + for (ThreadInfo ti : tinfos) { + if (ti.getStackTrace().length > 2) { + ThreadDump.printThreadInfo(ti); + throw new RuntimeException("more than requested " + + "number of frames dumped"); + } + } + + try { + tmxb.dumpAllThreads(true, true, -1); + throw new RuntimeException("Didn't throw IllegalArgumentException " + + "for negative maxdepth value"); + } catch (IllegalArgumentException e) { + System.out.println("Throwed IllegalArgumentException as expected"); + } + + System.out.println("Test passed"); + } +} diff --git a/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java b/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java index dcc6579f618..626602bf5ae 100644 --- a/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java +++ b/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java @@ -70,6 +70,7 @@ public class JdkQualifiedExportTest { static Set KNOWN_EXCEPTIONS = Set.of("jdk.internal.vm.ci/jdk.vm.ci.services", + "jdk.internal.vm.ci/jdk.vm.ci.runtime", "jdk.jsobject/jdk.internal.netscape.javascript.spi"); static void checkExports(ModuleDescriptor md) { diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 3623db4c5e5..63c9ae9b049 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -32,6 +32,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -73,6 +74,9 @@ public class VMProps implements Callable> { map.put("vm.aot", vmAOT()); // vm.cds is true if the VM is compiled with cds support. map.put("vm.cds", vmCDS()); + // vm.graal.enabled is true if Graal is used as JIT + map.put("vm.graal.enabled", isGraalEnabled()); + map.put("docker.support", dockerSupport()); vmGC(map); // vm.gc.X = true/false VMProps.dump(map); @@ -292,6 +296,73 @@ public class VMProps implements Callable> { } } + /** + * Check if Graal is used as JIT compiler. + * + * @return true if Graal is used as JIT compiler. + */ + protected String isGraalEnabled() { + // Graal is enabled if following conditions are true: + // - we are not in Interpreter mode + // - UseJVMCICompiler flag is true + // - jvmci.Compiler variable is equal to 'graal' + // - TieredCompilation is not used or TieredStopAtLevel is greater than 3 + + Boolean useCompiler = WB.getBooleanVMFlag("UseCompiler"); + if (useCompiler == null || !useCompiler) + return "false"; + + Boolean useJvmciComp = WB.getBooleanVMFlag("UseJVMCICompiler"); + if (useJvmciComp == null || !useJvmciComp) + return "false"; + + // This check might be redundant but let's keep it for now. + String jvmciCompiler = System.getProperty("jvmci.Compiler"); + if (jvmciCompiler == null || !jvmciCompiler.equals("graal")) { + return "false"; + } + + Boolean tieredCompilation = WB.getBooleanVMFlag("TieredCompilation"); + Long compLevel = WB.getIntxVMFlag("TieredStopAtLevel"); + // if TieredCompilation is enabled and compilation level is <= 3 then no Graal is used + if (tieredCompilation != null && tieredCompilation && compLevel != null && compLevel <= 3) + return "false"; + + return "true"; + } + + + /** + * A simple check for docker support + * + * @return true if docker is supported in a given environment + */ + protected String dockerSupport() { + // currently docker testing is only supported for Linux-x64 + if (! ( Platform.isLinux() && Platform.isX64() ) ) + return "false"; + + boolean isSupported; + try { + isSupported = checkDockerSupport(); + } catch (Exception e) { + isSupported = false; + System.err.println("dockerSupport() threw exception: " + e); + } + + return (isSupported) ? "true" : "false"; + } + + private boolean checkDockerSupport() throws IOException, InterruptedException { + ProcessBuilder pb = new ProcessBuilder("docker", "ps"); + Process p = pb.start(); + p.waitFor(10, TimeUnit.SECONDS); + + return (p.exitValue() == 0); + } + + + /** * Dumps the map to the file if the file name is given as the property. * This functionality could be helpful to know context in the real diff --git a/test/lib/jdk/test/lib/FileInstaller.java b/test/lib/jdk/test/lib/FileInstaller.java index 1247deedcb1..73bc23f3238 100644 --- a/test/lib/jdk/test/lib/FileInstaller.java +++ b/test/lib/jdk/test/lib/FileInstaller.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -32,11 +32,18 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; +// !!! +// NOTE: this class is widely used. DO NOT depend on any other classes in any test library, or else +// you may see intermittent ClassNotFoundException as in JDK-8188828 +// !!! + /** * Copy a resource: file or directory recursively, using relative path(src and dst) * which are applied to test source directory(src) and current directory(dst) */ public class FileInstaller { + public static final String TEST_SRC = System.getProperty("test.src", "").trim(); + /** * @param args source and destination * @throws IOException if an I/O error occurs @@ -45,10 +52,12 @@ public class FileInstaller { if (args.length != 2) { throw new IllegalArgumentException("Unexpected number of arguments for file copy"); } - Path src = Paths.get(Utils.TEST_SRC, args[0]).toAbsolutePath(); - Path dst = Paths.get(args[1]).toAbsolutePath(); + Path src = Paths.get(TEST_SRC, args[0]).toAbsolutePath().normalize(); + Path dst = Paths.get(args[1]).toAbsolutePath().normalize(); if (src.toFile().exists()) { + System.out.printf("copying %s to %s%n", src, dst); if (src.toFile().isDirectory()) { + // can't use Files::copy for dirs, as 'dst' might exist already Files.walkFileTree(src, new CopyFileVisitor(src, dst)); } else { Path dstDir = dst.getParent(); @@ -74,7 +83,7 @@ public class FileInstaller { @Override public FileVisitResult preVisitDirectory(Path file, BasicFileAttributes attrs) throws IOException { - Path relativePath = file.relativize(copyFrom); + Path relativePath = copyFrom.relativize(file); Path destination = copyTo.resolve(relativePath); if (!destination.toFile().exists()) { Files.createDirectories(destination); diff --git a/test/lib/jdk/test/lib/cds/CDSTestUtils.java b/test/lib/jdk/test/lib/cds/CDSTestUtils.java index 16a32056ff3..8d0f9ef4bcb 100644 --- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java @@ -26,7 +26,9 @@ import java.io.IOException; import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -60,6 +62,8 @@ public class CDSTestUtils { public static OutputAnalyzer createArchive(CDSOptions opts) throws Exception { + startNewArchiveName(); + ArrayList cmd = new ArrayList(); for (String p : opts.prefix) cmd.add(p); @@ -328,9 +332,19 @@ public class CDSTestUtils { return testName; } + private static final SimpleDateFormat timeStampFormat = + new SimpleDateFormat("HH'h'mm'm'ss's'SSS"); + + private static String defaultArchiveName; + + // Call this method to start new archive with new unique name + public static void startNewArchiveName() { + defaultArchiveName = getTestName() + + timeStampFormat.format(new Date()) + ".jsa"; + } public static String getDefaultArchiveName() { - return getTestName() + ".jsa"; + return defaultArchiveName; } diff --git a/test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java b/test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java new file mode 100644 index 00000000000..254edb86cb7 --- /dev/null +++ b/test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017, 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.test.lib.containers.docker; + +import java.util.ArrayList; +import java.util.Collections; + + +// This class represents options for running java inside docker containers +// in test environment. +public class DockerRunOptions { + public String imageNameAndTag; + public ArrayList dockerOpts = new ArrayList(); + public String command; // normally a full path to java + public ArrayList javaOpts = new ArrayList(); + public String classToRun; // class or "-version" + public ArrayList classParams = new ArrayList(); + + public boolean tty = true; + public boolean removeContainerAfterUse = true; + public boolean appendTestJavaOptions = true; + public boolean retainChildStdout = false; + + /** + * Convenience constructor for most common use cases in testing. + * @param imageNameAndTag a string representing name and tag for the + * docker image to run, as "name:tag" + * @param javaCmd a java command to run (e.g. /jdk/bin/java) + * @param classToRun a class to run, or "-version" + * @param javaOpts java options to use + * + * @return Default docker run options + */ + public DockerRunOptions(String imageNameAndTag, String javaCmd, + String classToRun, String... javaOpts) { + this.imageNameAndTag = imageNameAndTag; + this.command = javaCmd; + this.classToRun = classToRun; + this.addJavaOpts(javaOpts); + } + + public DockerRunOptions addDockerOpts(String... opts) { + Collections.addAll(dockerOpts, opts); + return this; + } + + public DockerRunOptions addJavaOpts(String... opts) { + Collections.addAll(javaOpts, opts); + return this; + } + +} diff --git a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java new file mode 100644 index 00000000000..b9b84dbd29f --- /dev/null +++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2017, 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.test.lib.containers.docker; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.FileVisitResult; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + + +public class DockerTestUtils { + private static final String FS = File.separator; + private static boolean isDockerEngineAvailable = false; + private static boolean wasDockerEngineChecked = false; + + // Diagnostics: set to true to enable more diagnostic info + private static final boolean DEBUG = false; + + /** + * Optimized check of whether the docker engine is available in a given + * environment. Checks only once, then remembers the result in a singleton. + * + * @return true if docker engine is available + * @throws Exception + */ + public static boolean isDockerEngineAvailable() throws Exception { + if (wasDockerEngineChecked) + return isDockerEngineAvailable; + + isDockerEngineAvailable = isDockerEngineAvailableCheck(); + wasDockerEngineChecked = true; + return isDockerEngineAvailable; + } + + + /** + * Convenience method, will check if docker engine is available and usable; + * will print the appropriate message when not available. + * + * @return true if docker engine is available + * @throws Exception + */ + public static boolean canTestDocker() throws Exception { + if (isDockerEngineAvailable()) { + return true; + } else { + System.out.println("Docker engine is not available on this system"); + System.out.println("This test is SKIPPED"); + return false; + } + } + + + /** + * Simple check - is docker engine available, accessible and usable. + * Run basic docker command: 'docker ps' - list docker instances. + * If docker engine is available and accesible then true is returned + * and we can proceed with testing docker. + * + * @return true if docker engine is available and usable + * @throws Exception + */ + private static boolean isDockerEngineAvailableCheck() throws Exception { + try { + execute("docker", "ps") + .shouldHaveExitValue(0) + .shouldContain("CONTAINER") + .shouldContain("IMAGE"); + } catch (Exception e) { + return false; + } + return true; + } + + + /** + * Build a docker image that contains JDK under test. + * The jdk will be placed under the "/jdk/" folder inside the docker file system. + * + * @param imageName name of the image to be created, including version tag + * @param dockerfile name of the dockerfile residing in the test source + * @param buildDirName name of the docker build/staging directory, which will + * be created in the jtreg's scratch folder + * @throws Exception + */ + public static void + buildJdkDockerImage(String imageName, String dockerfile, String buildDirName) + throws Exception { + + Path buildDir = Paths.get(".", buildDirName); + if (Files.exists(buildDir)) { + throw new RuntimeException("The docker build directory already exists: " + buildDir); + } + + Path jdkSrcDir = Paths.get(Utils.TEST_JDK); + Path jdkDstDir = buildDir.resolve("jdk"); + + Files.createDirectories(jdkDstDir); + + // Copy JDK-under-test tree to the docker build directory. + // This step is required for building a docker image. + Files.walkFileTree(jdkSrcDir, new CopyFileVisitor(jdkSrcDir, jdkDstDir)); + buildDockerImage(imageName, Paths.get(Utils.TEST_SRC, dockerfile), buildDir); + } + + + /** + * Build a docker image based on given docker file and docker build directory. + * + * @param imageName name of the image to be created, including version tag + * @param dockerfile path to the Dockerfile to be used for building the docker + * image. The specified dockerfile will be copied to the docker build + * directory as 'Dockerfile' + * @param buildDir build directory; it should already contain all the content + * needed to build the docker image. + * @throws Exception + */ + public static void + buildDockerImage(String imageName, Path dockerfile, Path buildDir) throws Exception { + + // Copy docker file to the build dir + Files.copy(dockerfile, buildDir.resolve("Dockerfile")); + + // Build the docker + execute("docker", "build", buildDir.toString(), "--no-cache", "--tag", imageName) + .shouldHaveExitValue(0) + .shouldContain("Successfully built"); + } + + + /** + * Run Java inside the docker image with specified parameters and options. + * + * @param DockerRunOptions optins for running docker + * + * @return output of the run command + * @throws Exception + */ + public static OutputAnalyzer dockerRunJava(DockerRunOptions opts) throws Exception { + ArrayList cmd = new ArrayList<>(); + + cmd.add("docker"); + cmd.add("run"); + if (opts.tty) + cmd.add("--tty=true"); + if (opts.removeContainerAfterUse) + cmd.add("--rm"); + + cmd.addAll(opts.dockerOpts); + cmd.add(opts.imageNameAndTag); + cmd.add(opts.command); + + cmd.addAll(opts.javaOpts); + if (opts.appendTestJavaOptions) { + Collections.addAll(cmd, Utils.getTestJavaOpts()); + } + + cmd.add(opts.classToRun); + cmd.addAll(opts.classParams); + + return execute(cmd); + } + + + /** + * Remove docker image + * + * @param DockerRunOptions optins for running docker + * @return output of the command + * @throws Exception + */ + public static OutputAnalyzer removeDockerImage(String imageNameAndTag) throws Exception { + return execute("docker", "rmi", "--force", imageNameAndTag); + } + + + + /** + * Convenience method - express command as sequence of strings + * + * @param command to execute + * @return The output from the process + * @throws Exception + */ + public static OutputAnalyzer execute(List command) throws Exception { + return execute(command.toArray(new String[command.size()])); + } + + + /** + * Execute a specified command in a process, report diagnostic info. + * + * @param command to be executed + * @return The output from the process + * @throws Exception + */ + public static OutputAnalyzer execute(String... command) throws Exception { + + ProcessBuilder pb = new ProcessBuilder(command); + System.out.println("[COMMAND]\n" + Utils.getCommandLine(pb)); + + long started = System.currentTimeMillis(); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + System.out.println("[ELAPSED: " + (System.currentTimeMillis() - started) + " ms]"); + System.out.println("[STDERR]\n" + output.getStderr()); + System.out.println("[STDOUT]\n" + output.getStdout()); + + return output; + } + + + private static class CopyFileVisitor extends SimpleFileVisitor { + private final Path src; + private final Path dst; + + public CopyFileVisitor(Path src, Path dst) { + this.src = src; + this.dst = dst; + } + + + @Override + public FileVisitResult preVisitDirectory(Path file, + BasicFileAttributes attrs) throws IOException { + Path dstDir = dst.resolve(src.relativize(file)); + if (!dstDir.toFile().exists()) { + Files.createDirectories(dstDir); + } + return FileVisitResult.CONTINUE; + } + + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) throws IOException { + if (!file.toFile().isFile()) { + return FileVisitResult.CONTINUE; + } + Path dstFile = dst.resolve(src.relativize(file)); + Files.copy(file, dstFile, StandardCopyOption.COPY_ATTRIBUTES); + return FileVisitResult.CONTINUE; + } + } +}