--- a/.hgtags Tue Apr 09 16:11:54 2019 -0400
+++ b/.hgtags Thu Apr 11 07:44:51 2019 -0400
@@ -553,3 +553,4 @@
83cace4142c8563b6a921787db02388e1bc48d01 jdk-13+13
46cf212cdccaf4fb064d913b12004007d3322b67 jdk-13+14
f855ec13aa2501ae184c8b3e0626a8cec9966116 jdk-13+15
+9d0ae9508d5337b0dc7cc4684be42888c4023755 jdk-13+16
--- a/make/autoconf/basics.m4 Tue Apr 09 16:11:54 2019 -0400
+++ b/make/autoconf/basics.m4 Thu Apr 11 07:44:51 2019 -0400
@@ -883,10 +883,11 @@
fi
if test "x$CUSTOM_ROOT" != x; then
- OUTPUTDIR="${CUSTOM_ROOT}/build/${CONF_NAME}"
+ WORKSPACE_ROOT="${CUSTOM_ROOT}"
else
- OUTPUTDIR="${TOPDIR}/build/${CONF_NAME}"
+ WORKSPACE_ROOT="${TOPDIR}"
fi
+ OUTPUTDIR="${WORKSPACE_ROOT}/build/${CONF_NAME}"
$MKDIR -p "$OUTPUTDIR"
if test ! -d "$OUTPUTDIR"; then
AC_MSG_ERROR([Could not create build directory $OUTPUTDIR])
@@ -942,6 +943,7 @@
AC_SUBST(SPEC)
AC_SUBST(CONF_NAME)
AC_SUBST(OUTPUTDIR)
+ AC_SUBST(WORKSPACE_ROOT)
AC_SUBST(CONFIGURESUPPORT_OUTPUTDIR)
# The spec.gmk file contains all variables for the make system.
--- a/make/autoconf/flags-cflags.m4 Tue Apr 09 16:11:54 2019 -0400
+++ b/make/autoconf/flags-cflags.m4 Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -799,15 +799,29 @@
$1_WARNING_CFLAGS_JVM="-Wno-format-zero-length -Wtype-limits -Wuninitialized"
fi
+ if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
+ # Check if compiler supports -fmacro-prefix-map. If so, use that to make
+ # the __FILE__ macro resolve to paths relative to the workspace root.
+ workspace_root_trailing_slash="${WORKSPACE_ROOT%/}/"
+ FILE_MACRO_CFLAGS="-fmacro-prefix-map=${workspace_root_trailing_slash}="
+ FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${FILE_MACRO_CFLAGS}],
+ PREFIX: $3,
+ IF_FALSE: [
+ FILE_MACRO_CFLAGS=
+ ]
+ )
+ fi
+
# EXPORT to API
CFLAGS_JVM_COMMON="$ALWAYS_CFLAGS_JVM $ALWAYS_DEFINES_JVM \
$TOOLCHAIN_CFLAGS_JVM ${$1_TOOLCHAIN_CFLAGS_JVM} \
$OS_CFLAGS $OS_CFLAGS_JVM $CFLAGS_OS_DEF_JVM $DEBUG_CFLAGS_JVM \
- $WARNING_CFLAGS $WARNING_CFLAGS_JVM $JVM_PICFLAG"
+ $WARNING_CFLAGS $WARNING_CFLAGS_JVM $JVM_PICFLAG $FILE_MACRO_CFLAGS"
CFLAGS_JDK_COMMON="$ALWAYS_CFLAGS_JDK $ALWAYS_DEFINES_JDK $TOOLCHAIN_CFLAGS_JDK \
$OS_CFLAGS $CFLAGS_OS_DEF_JDK $DEBUG_CFLAGS_JDK $DEBUG_OPTIONS_FLAGS_JDK \
- $WARNING_CFLAGS $WARNING_CFLAGS_JDK $DEBUG_SYMBOLS_CFLAGS_JDK"
+ $WARNING_CFLAGS $WARNING_CFLAGS_JDK $DEBUG_SYMBOLS_CFLAGS_JDK \
+ $FILE_MACRO_CFLAGS"
# Use ${$2EXTRA_CFLAGS} to block EXTRA_CFLAGS to be added to build flags.
# (Currently we don't have any OPENJDK_BUILD_EXTRA_CFLAGS, but that might
--- a/make/autoconf/spec.gmk.in Tue Apr 09 16:11:54 2019 -0400
+++ b/make/autoconf/spec.gmk.in Thu Apr 11 07:44:51 2019 -0400
@@ -140,7 +140,9 @@
# The top-level directory of the source repository
TOPDIR:=@TOPDIR@
-
+# Usually the top level directory, but could be something else if a custom
+# root is defined.
+WORKSPACE_ROOT:=@WORKSPACE_ROOT@
IMPORT_MODULES_CLASSES:=@IMPORT_MODULES_CLASSES@
IMPORT_MODULES_CMDS:=@IMPORT_MODULES_CMDS@
IMPORT_MODULES_LIBS:=@IMPORT_MODULES_LIBS@
--- a/make/common/NativeCompilation.gmk Tue Apr 09 16:11:54 2019 -0400
+++ b/make/common/NativeCompilation.gmk Thu Apr 11 07:44:51 2019 -0400
@@ -236,8 +236,10 @@
# This is the definite source file to use for $1_FILENAME.
$1_SRC_FILE := $$($1_FILE)
- ifneq ($$($1_DISABLE_THIS_FILE_DEFINE), true)
- $1_THIS_FILE = -DTHIS_FILE='"$$($1_FILENAME)"'
+ ifneq ($$($1_DEFINE_THIS_FILE), false)
+ ifneq ($$($$($1_BASE)_DEFINE_THIS_FILE), false)
+ $1_THIS_FILE = -DTHIS_FILE='"$$($1_FILENAME)"'
+ endif
endif
ifeq ($$($1_OPTIMIZATION), )
@@ -370,6 +372,7 @@
$(ECHO) $$@: \\ > $$($1_DEPS_FILE) ; \
$(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_OBJ).log \
| $(SORT) -u >> $$($1_DEPS_FILE) ; \
+ $(ECHO) >> $$($1_DEPS_FILE) ; \
$(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_DEPS_FILE) > $$($1_DEPS_TARGETS_FILE)
endif
endif
@@ -427,6 +430,7 @@
# STRIPFLAGS Optionally change the flags given to the strip command
# PRECOMPILED_HEADER Header file to use as precompiled header
# PRECOMPILED_HEADER_EXCLUDE List of source files that should not use PCH
+# DEFINE_THIS_FILE Set to false to not set the THIS_FILE preprocessor macro
#
# After being called, some variables are exported from this macro, all prefixed
# with parameter 1 followed by a '_':
@@ -702,7 +706,7 @@
FILE := $$($1_GENERATED_PCH_SRC), \
BASE := $1, \
EXTRA_CXXFLAGS := -Fp$$($1_PCH_FILE) -Yc$$(notdir $$($1_PRECOMPILED_HEADER)), \
- DISABLE_THIS_FILE_DEFINE := true, \
+ DEFINE_THIS_FILE := false, \
))
$1_USE_PCH_FLAGS := \
@@ -839,6 +843,7 @@
$(ECHO) $$($1_RES): \\ > $$($1_RES_DEPS_FILE) ; \
$(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_RES_DEPS_FILE).obj.log \
>> $$($1_RES_DEPS_FILE) ; \
+ $(ECHO) >> $$($1_RES_DEPS_FILE) ;\
$(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_RES_DEPS_FILE) \
> $$($1_RES_DEPS_TARGETS_FILE)
endif
--- a/make/hotspot/gensrc/GensrcAdlc.gmk Tue Apr 09 16:11:54 2019 -0400
+++ b/make/hotspot/gensrc/GensrcAdlc.gmk Thu Apr 11 07:44:51 2019 -0400
@@ -76,6 +76,7 @@
DEBUG_SYMBOLS := false, \
DISABLED_WARNINGS_clang := tautological-compare, \
DISABLED_WARNINGS_solstudio := notemsource, \
+ DEFINE_THIS_FILE := false, \
))
ADLC_TOOL := $(BUILD_ADLC_TARGET)
--- a/make/hotspot/gensrc/GensrcDtrace.gmk Tue Apr 09 16:11:54 2019 -0400
+++ b/make/hotspot/gensrc/GensrcDtrace.gmk Thu Apr 11 07:44:51 2019 -0400
@@ -80,6 +80,7 @@
EXTRA_DEPS := $(JVMTI_H) $(JFR_FILES), \
OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets/objs, \
OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets, \
+ DEFINE_THIS_FILE := false, \
))
DTRACE_GEN_OFFSETS_TOOL := $(BUILD_DTRACE_GEN_OFFSETS_TARGET)
--- a/make/hotspot/lib/CompileDtraceLibraries.gmk Tue Apr 09 16:11:54 2019 -0400
+++ b/make/hotspot/lib/CompileDtraceLibraries.gmk Thu Apr 11 07:44:51 2019 -0400
@@ -42,6 +42,7 @@
LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
LIBS := $(LIBDL) -lthread -ldoor, \
OBJECT_DIR := $(LIBJVM_DTRACE_OUTPUTDIR)/objs, \
+ DEFINE_THIS_FILE := false, \
))
# Note that libjvm_db.c has tests for COMPILER2, but this was never set by
@@ -54,6 +55,7 @@
CFLAGS := -I$(DTRACE_GENSRC_DIR) $(JNI_INCLUDE_FLAGS) -m64 -G -mt -KPIC -xldscope=hidden, \
LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
OBJECT_DIR := $(LIBJVM_DB_OUTPUTDIR)/objs, \
+ DEFINE_THIS_FILE := false, \
))
TARGETS += $(BUILD_LIBJVM_DTRACE) $(BUILD_LIBJVM_DB)
--- a/make/hotspot/lib/CompileGtest.gmk Tue Apr 09 16:11:54 2019 -0400
+++ b/make/hotspot/lib/CompileGtest.gmk Thu Apr 11 07:44:51 2019 -0400
@@ -92,6 +92,7 @@
STRIP_SYMBOLS := false, \
PRECOMPILED_HEADER := $(JVM_PRECOMPILED_HEADER), \
PRECOMPILED_HEADER_EXCLUDE := gtest-all.cc gtestMain.cpp, \
+ DEFINE_THIS_FILE := false, \
))
TARGETS += $(BUILD_GTEST_LIBJVM)
@@ -115,6 +116,7 @@
LIBS_windows := $(JVM_OUTPUTDIR)/gtest/objs/jvm.lib, \
COPY_DEBUG_SYMBOLS := $(GTEST_COPY_DEBUG_SYMBOLS), \
ZIP_EXTERNAL_DEBUG_SYMBOLS := false, \
+ DEFINE_THIS_FILE := false, \
))
$(BUILD_GTEST_LAUNCHER): $(BUILD_GTEST_LIBJVM)
--- a/make/hotspot/lib/CompileJvm.gmk Tue Apr 09 16:11:54 2019 -0400
+++ b/make/hotspot/lib/CompileJvm.gmk Thu Apr 11 07:44:51 2019 -0400
@@ -202,6 +202,7 @@
VERSIONINFO_RESOURCE := $(TOPDIR)/src/hotspot/os/windows/version.rc, \
PRECOMPILED_HEADER := $(JVM_PRECOMPILED_HEADER), \
PRECOMPILED_HEADER_EXCLUDE := $(JVM_PRECOMPILED_HEADER_EXCLUDE), \
+ DEFINE_THIS_FILE := false, \
))
# Always recompile vm_version.cpp if libjvm needs to be relinked. This ensures
--- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -381,6 +381,27 @@
}
}
+void VM_Version::print_platform_virtualization_info(outputStream* st) {
+ const char* info_file = "/proc/ppc64/lparcfg";
+ const char* kw[] = { "system_type=", // qemu indicates PowerKVM
+ "partition_entitled_capacity=", // entitled processor capacity percentage
+ "partition_max_entitled_capacity=",
+ "capacity_weight=", // partition CPU weight
+ "partition_active_processors=",
+ "partition_potential_processors=",
+ "entitled_proc_capacity_available=",
+ "capped=", // 0 - uncapped, 1 - vcpus capped at entitled processor capacity percentage
+ "shared_processor_mode=", // (non)dedicated partition
+ "system_potential_processors=",
+ "pool=", // CPU-pool number
+ "pool_capacity=",
+ "NumLpars=", // on non-KVM machines, NumLpars is not found for full partition mode machines
+ NULL };
+ if (!print_matching_lines_from_file(info_file, st, kw)) {
+ st->print_cr(" <%s Not Available>", info_file);
+ }
+}
+
bool VM_Version::use_biased_locking() {
#if INCLUDE_RTM_OPT
// RTM locking is most useful when there is high lock contention and
--- a/src/hotspot/cpu/ppc/vm_version_ppc.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/cpu/ppc/vm_version_ppc.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -89,6 +89,9 @@
static void initialize();
// Override Abstract_VM_Version implementation
+ static void print_platform_virtualization_info(outputStream*);
+
+ // Override Abstract_VM_Version implementation
static bool use_biased_locking();
static bool is_determine_features_test_running() { return _is_determine_features_test_running; }
--- a/src/hotspot/cpu/s390/vm_version_s390.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/cpu/s390/vm_version_s390.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -516,6 +516,19 @@
}
}
+void VM_Version::print_platform_virtualization_info(outputStream* st) {
+ // /proc/sysinfo contains interesting information about
+ // - LPAR
+ // - whole "Box" (CPUs )
+ // - z/VM / KVM (VM<nn>); this is not available in an LPAR-only setup
+ const char* kw[] = { "LPAR", "CPUs", "VM", NULL };
+ const char* info_file = "/proc/sysinfo";
+
+ if (!print_matching_lines_from_file(info_file, st, kw)) {
+ st->print_cr(" <%s Not Available>", info_file);
+ }
+}
+
void VM_Version::print_features() {
print_features_internal("Version:");
}
--- a/src/hotspot/cpu/s390/vm_version_s390.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/cpu/s390/vm_version_s390.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -346,6 +346,9 @@
static void print_features();
static bool is_determine_features_test_running() { return _is_determine_features_test_running; }
+ // Override Abstract_VM_Version implementation
+ static void print_platform_virtualization_info(outputStream*);
+
// CPU feature query functions
static const char* get_model_string() { return _model_string; }
static bool has_StoreFacilityListExtended() { return (_features[0] & StoreFacilityListExtendedMask) == StoreFacilityListExtendedMask; }
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1573,6 +1573,65 @@
#endif // !PRODUCT
}
+void VM_Version::print_platform_virtualization_info(outputStream* st) {
+ VirtualizationType vrt = VM_Version::get_detected_virtualization();
+ if (vrt == XenHVM) {
+ st->print_cr("Xen hardware-assisted virtualization detected");
+ } else if (vrt == KVM) {
+ st->print_cr("KVM virtualization detected");
+ } else if (vrt == VMWare) {
+ st->print_cr("VMWare virtualization detected");
+ } else if (vrt == HyperV) {
+ st->print_cr("HyperV virtualization detected");
+ }
+}
+
+void VM_Version::check_virt_cpuid(uint32_t idx, uint32_t *regs) {
+// TODO support 32 bit
+#if defined(_LP64)
+#if defined(_MSC_VER)
+ // Allocate space for the code
+ const int code_size = 100;
+ ResourceMark rm;
+ CodeBuffer cb("detect_virt", code_size, 0);
+ MacroAssembler* a = new MacroAssembler(&cb);
+ address code = a->pc();
+ void (*test)(uint32_t idx, uint32_t *regs) = (void(*)(uint32_t idx, uint32_t *regs))code;
+
+ a->movq(r9, rbx); // save nonvolatile register
+
+ // next line would not work on 32-bit
+ a->movq(rax, c_rarg0 /* rcx */);
+ a->movq(r8, c_rarg1 /* rdx */);
+ a->cpuid();
+ a->movl(Address(r8, 0), rax);
+ a->movl(Address(r8, 4), rbx);
+ a->movl(Address(r8, 8), rcx);
+ a->movl(Address(r8, 12), rdx);
+
+ a->movq(rbx, r9); // restore nonvolatile register
+ a->ret(0);
+
+ uint32_t *code_end = (uint32_t *)a->pc();
+ a->flush();
+
+ // execute code
+ (*test)(idx, regs);
+#elif defined(__GNUC__)
+ __asm__ volatile (
+ " cpuid;"
+ " mov %%eax,(%1);"
+ " mov %%ebx,4(%1);"
+ " mov %%ecx,8(%1);"
+ " mov %%edx,12(%1);"
+ : "+a" (idx)
+ : "S" (regs)
+ : "ebx", "ecx", "edx", "memory" );
+#endif
+#endif
+}
+
+
bool VM_Version::use_biased_locking() {
#if INCLUDE_RTM_OPT
// RTM locking is most useful when there is high lock contention and
@@ -1594,6 +1653,54 @@
return UseBiasedLocking;
}
+// On Xen, the cpuid instruction returns
+// eax / registers[0]: Version of Xen
+// ebx / registers[1]: chars 'XenV'
+// ecx / registers[2]: chars 'MMXe'
+// edx / registers[3]: chars 'nVMM'
+//
+// On KVM / VMWare / MS Hyper-V, the cpuid instruction returns
+// ebx / registers[1]: chars 'KVMK' / 'VMwa' / 'Micr'
+// ecx / registers[2]: chars 'VMKV' / 'reVM' / 'osof'
+// edx / registers[3]: chars 'M' / 'ware' / 't Hv'
+//
+// more information :
+// https://kb.vmware.com/s/article/1009458
+//
+void VM_Version::check_virtualizations() {
+#if defined(_LP64)
+ uint32_t registers[4];
+ char signature[13];
+ uint32_t base;
+ signature[12] = '\0';
+ memset((void*)registers, 0, 4*sizeof(uint32_t));
+
+ for (base = 0x40000000; base < 0x40010000; base += 0x100) {
+ check_virt_cpuid(base, registers);
+
+ *(uint32_t *)(signature + 0) = registers[1];
+ *(uint32_t *)(signature + 4) = registers[2];
+ *(uint32_t *)(signature + 8) = registers[3];
+
+ if (strncmp("VMwareVMware", signature, 12) == 0) {
+ Abstract_VM_Version::_detected_virtualization = VMWare;
+ }
+
+ if (strncmp("Microsoft Hv", signature, 12) == 0) {
+ Abstract_VM_Version::_detected_virtualization = HyperV;
+ }
+
+ if (strncmp("KVMKVMKVM", signature, 9) == 0) {
+ Abstract_VM_Version::_detected_virtualization = KVM;
+ }
+
+ if (strncmp("XenVMMXenVMM", signature, 12) == 0) {
+ Abstract_VM_Version::_detected_virtualization = XenHVM;
+ }
+ }
+#endif
+}
+
void VM_Version::initialize() {
ResourceMark rm;
// Making this stub must be FIRST use of assembler
@@ -1608,4 +1715,7 @@
g.generate_get_cpu_info());
get_processor_features();
+ if (cpu_family() > 4) { // it supports CPUID
+ check_virtualizations();
+ }
}
--- a/src/hotspot/cpu/x86/vm_version_x86.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/cpu/x86/vm_version_x86.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -686,6 +686,9 @@
static void initialize();
// Override Abstract_VM_Version implementation
+ static void print_platform_virtualization_info(outputStream*);
+
+ // Override Abstract_VM_Version implementation
static bool use_biased_locking();
// Asserts
@@ -930,6 +933,11 @@
// that can be used for efficient implementation of
// the intrinsic for java.lang.Thread.onSpinWait()
static bool supports_on_spin_wait() { return supports_sse2(); }
+
+ // support functions for virtualization detection
+ private:
+ static void check_virt_cpuid(uint32_t idx, uint32_t *regs);
+ static void check_virtualizations();
};
#endif // CPU_X86_VM_VERSION_X86_HPP
--- a/src/hotspot/cpu/zero/cppInterpreter_zero.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/cpu/zero/cppInterpreter_zero.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -371,14 +371,12 @@
intptr_t result[4 - LogBytesPerWord];
ffi_call(handler->cif(), (void (*)()) function, result, arguments);
- // Change the thread state back to _thread_in_Java.
+ // Change the thread state back to _thread_in_Java and ensure it
+ // is seen by the GC thread.
// ThreadStateTransition::transition_from_native() cannot be used
// here because it does not check for asynchronous exceptions.
// We have to manage the transition ourself.
- thread->set_thread_state(_thread_in_native_trans);
-
- // Make sure new state is visible in the GC thread
- InterfaceSupport::serialize_thread_state(thread);
+ thread->set_thread_state_fence(_thread_in_native_trans);
// Handle safepoint operations, pending suspend requests,
// and pending asynchronous exceptions.
--- a/src/hotspot/os/aix/os_perf_aix.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/os/aix/os_perf_aix.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -273,98 +273,12 @@
return n;
}
-static FILE* open_statfile(void) {
- FILE *f;
-
- if ((f = fopen("/proc/stat", "r")) == NULL) {
- static int haveWarned = 0;
- if (!haveWarned) {
- haveWarned = 1;
- }
- }
- return f;
-}
-
-static void
-next_line(FILE *f) {
- int c;
- do {
- c = fgetc(f);
- } while (c != '\n' && c != EOF);
-}
-
/**
- * Return the total number of ticks since the system was booted.
- * If the usedTicks parameter is not NULL, it will be filled with
- * the number of ticks spent on actual processes (user, system or
- * nice processes) since system boot. Note that this is the total number
- * of "executed" ticks on _all_ CPU:s, that is on a n-way system it is
- * n times the number of ticks that has passed in clock time.
- *
- * Returns a negative value if the reading of the ticks failed.
+ * on Linux we got the ticks related information from /proc/stat
+ * this does not work on AIX, libperfstat might be an alternative
*/
static OSReturn get_total_ticks(int which_logical_cpu, CPUPerfTicks* pticks) {
- FILE* fh;
- uint64_t userTicks, niceTicks, systemTicks, idleTicks;
- uint64_t iowTicks = 0, irqTicks = 0, sirqTicks= 0;
- int logical_cpu = -1;
- const int expected_assign_count = (-1 == which_logical_cpu) ? 4 : 5;
- int n;
-
- if ((fh = open_statfile()) == NULL) {
- return OS_ERR;
- }
- if (-1 == which_logical_cpu) {
- n = fscanf(fh, "cpu " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
- UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,
- &userTicks, &niceTicks, &systemTicks, &idleTicks,
- &iowTicks, &irqTicks, &sirqTicks);
- } else {
- // Move to next line
- next_line(fh);
-
- // find the line for requested cpu faster to just iterate linefeeds?
- for (int i = 0; i < which_logical_cpu; i++) {
- next_line(fh);
- }
-
- n = fscanf(fh, "cpu%u " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
- UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,
- &logical_cpu, &userTicks, &niceTicks,
- &systemTicks, &idleTicks, &iowTicks, &irqTicks, &sirqTicks);
- }
-
- fclose(fh);
- if (n < expected_assign_count || logical_cpu != which_logical_cpu) {
- return OS_ERR;
- }
- pticks->used = userTicks + niceTicks;
- pticks->usedKernel = systemTicks + irqTicks + sirqTicks;
- pticks->total = userTicks + niceTicks + systemTicks + idleTicks +
- iowTicks + irqTicks + sirqTicks;
-
- return OS_OK;
-}
-
-
-static int get_systemtype(void) {
- static int procEntriesType = UNDETECTED;
- DIR *taskDir;
-
- if (procEntriesType != UNDETECTED) {
- return procEntriesType;
- }
-
- // Check whether we have a task subdirectory
- if ((taskDir = opendir("/proc/self/task")) == NULL) {
- procEntriesType = UNDETECTABLE;
- } else {
- // The task subdirectory exists; we're on a Linux >= 2.6 system
- closedir(taskDir);
- procEntriesType = LINUX26_NPTL;
- }
-
- return procEntriesType;
+ return OS_ERR;
}
/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */
@@ -378,26 +292,7 @@
* to the JVM on any CPU.
*/
static OSReturn get_jvm_ticks(CPUPerfTicks* pticks) {
- uint64_t userTicks;
- uint64_t systemTicks;
-
- if (get_systemtype() != LINUX26_NPTL) {
- return OS_ERR;
- }
-
- if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) != 2) {
- return OS_ERR;
- }
-
- // get the total
- if (get_total_ticks(-1, pticks) != OS_OK) {
- return OS_ERR;
- }
-
- pticks->used = userTicks;
- pticks->usedKernel = systemTicks;
-
- return OS_OK;
+ return OS_ERR;
}
/**
@@ -461,29 +356,7 @@
}
static int SCANF_ARGS(1, 2) parse_stat(_SCANFMT_ const char* fmt, ...) {
- FILE *f;
- va_list args;
-
- va_start(args, fmt);
-
- if ((f = open_statfile()) == NULL) {
- va_end(args);
- return OS_ERR;
- }
- for (;;) {
- char line[80];
- if (fgets(line, sizeof(line), f) != NULL) {
- if (vsscanf(line, fmt, args) == 1) {
- fclose(f);
- va_end(args);
- return OS_OK;
- }
- } else {
- fclose(f);
- va_end(args);
- return OS_ERR;
- }
- }
+ return OS_ERR;
}
static int get_noof_context_switches(uint64_t* switches) {
--- a/src/hotspot/os/linux/os_linux.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/os/linux/os_linux.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -63,6 +63,7 @@
#include "runtime/threadCritical.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/timer.hpp"
+#include "runtime/vm_version.hpp"
#include "semaphore_posix.hpp"
#include "services/attachListener.hpp"
#include "services/memTracker.hpp"
@@ -1939,35 +1940,6 @@
return true;
}
-#if defined(S390) || defined(PPC64)
-// keywords_to_match - NULL terminated array of keywords
-static bool print_matching_lines_from_file(const char* filename, outputStream* st, const char* keywords_to_match[]) {
- char* line = NULL;
- size_t length = 0;
- FILE* fp = fopen(filename, "r");
- if (fp == NULL) {
- return false;
- }
-
- st->print_cr("Virtualization information:");
- while (getline(&line, &length, fp) != -1) {
- int i = 0;
- while (keywords_to_match[i] != NULL) {
- if (strncmp(line, keywords_to_match[i], strlen(keywords_to_match[i])) == 0) {
- st->print("%s", line);
- break;
- }
- i++;
- }
- }
-
- free(line);
- fclose(fp);
-
- return true;
-}
-#endif
-
void os::print_dll_info(outputStream *st) {
st->print_cr("Dynamic libraries:");
@@ -2052,7 +2024,7 @@
os::Linux::print_container_info(st);
- os::Linux::print_virtualization_info(st);
+ VM_Version::print_platform_virtualization_info(st);
os::Linux::print_steal_info(st);
}
@@ -2309,40 +2281,6 @@
st->cr();
}
-void os::Linux::print_virtualization_info(outputStream* st) {
-#if defined(S390)
- // /proc/sysinfo contains interesting information about
- // - LPAR
- // - whole "Box" (CPUs )
- // - z/VM / KVM (VM<nn>); this is not available in an LPAR-only setup
- const char* kw[] = { "LPAR", "CPUs", "VM", NULL };
- const char* info_file = "/proc/sysinfo";
-
- if (!print_matching_lines_from_file(info_file, st, kw)) {
- st->print_cr(" <%s Not Available>", info_file);
- }
-#elif defined(PPC64)
- const char* info_file = "/proc/ppc64/lparcfg";
- const char* kw[] = { "system_type=", // qemu indicates PowerKVM
- "partition_entitled_capacity=", // entitled processor capacity percentage
- "partition_max_entitled_capacity=",
- "capacity_weight=", // partition CPU weight
- "partition_active_processors=",
- "partition_potential_processors=",
- "entitled_proc_capacity_available=",
- "capped=", // 0 - uncapped, 1 - vcpus capped at entitled processor capacity percentage
- "shared_processor_mode=", // (non)dedicated partition
- "system_potential_processors=",
- "pool=", // CPU-pool number
- "pool_capacity=",
- "NumLpars=", // on non-KVM machines, NumLpars is not found for full partition mode machines
- NULL };
- if (!print_matching_lines_from_file(info_file, st, kw)) {
- st->print_cr(" <%s Not Available>", info_file);
- }
-#endif
-}
-
void os::Linux::print_steal_info(outputStream* st) {
if (has_initial_tick_info) {
CPUPerfTicks pticks;
--- a/src/hotspot/os/linux/os_linux.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/os/linux/os_linux.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -108,7 +108,6 @@
static void print_full_memory_info(outputStream* st);
static void print_container_info(outputStream* st);
- static void print_virtualization_info(outputStream* st);
static void print_steal_info(outputStream* st);
static void print_distro_info(outputStream* st);
static void print_libversion_info(outputStream* st);
--- a/src/hotspot/os/windows/os_windows.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/os/windows/os_windows.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -1601,6 +1601,10 @@
#endif
st->print("OS:");
os::win32::print_windows_version(st);
+
+#ifdef _LP64
+ VM_Version::print_platform_virtualization_info(st);
+#endif
}
void os::win32::print_windows_version(outputStream* st) {
--- a/src/hotspot/share/classfile/javaClasses.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/classfile/javaClasses.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -160,6 +160,7 @@
int java_lang_String::value_offset = 0;
int java_lang_String::hash_offset = 0;
+int java_lang_String::hashIsZero_offset = 0;
int java_lang_String::coder_offset = 0;
bool java_lang_String::initialized = false;
@@ -179,7 +180,8 @@
#define STRING_FIELDS_DO(macro) \
macro(value_offset, k, vmSymbols::value_name(), byte_array_signature, false); \
macro(hash_offset, k, "hash", int_signature, false); \
- macro(coder_offset, k, "coder", byte_signature, false)
+ macro(hashIsZero_offset, k, "hashIsZero", bool_signature, false); \
+ macro(coder_offset, k, "coder", byte_signature, false);
void java_lang_String::compute_offsets() {
if (initialized) {
@@ -507,18 +509,38 @@
}
unsigned int java_lang_String::hash_code(oop java_string) {
- typeArrayOop value = java_lang_String::value(java_string);
- int length = java_lang_String::length(java_string, value);
- // Zero length string will hash to zero with String.hashCode() function.
- if (length == 0) return 0;
-
- bool is_latin1 = java_lang_String::is_latin1(java_string);
-
- if (is_latin1) {
- return java_lang_String::hash_code(value->byte_at_addr(0), length);
+ // The hash and hashIsZero fields are subject to a benign data race,
+ // making it crucial to ensure that any observable result of the
+ // calculation in this method stays correct under any possible read of
+ // these fields. Necessary restrictions to allow this to be correct
+ // without explicit memory fences or similar concurrency primitives is
+ // that we can ever only write to one of these two fields for a given
+ // String instance, and that the computation is idempotent and derived
+ // from immutable state
+ assert(initialized && (hash_offset > 0) && (hashIsZero_offset > 0), "Must be initialized");
+ if (java_lang_String::hash_is_set(java_string)) {
+ return java_string->int_field(hash_offset);
+ }
+
+ typeArrayOop value = java_lang_String::value(java_string);
+ int length = java_lang_String::length(java_string, value);
+ bool is_latin1 = java_lang_String::is_latin1(java_string);
+
+ unsigned int hash = 0;
+ if (length > 0) {
+ if (is_latin1) {
+ hash = java_lang_String::hash_code(value->byte_at_addr(0), length);
+ } else {
+ hash = java_lang_String::hash_code(value->char_at_addr(0), length);
+ }
+ }
+
+ if (hash != 0) {
+ java_string->int_field_put(hash_offset, hash);
} else {
- return java_lang_String::hash_code(value->char_at_addr(0), length);
+ java_string->bool_field_put(hashIsZero_offset, true);
}
+ return hash;
}
char* java_lang_String::as_quoted_ascii(oop java_string) {
@@ -3613,23 +3635,48 @@
resolved_method->address_field_put(_vmtarget_offset, (address)m);
}
+void java_lang_invoke_ResolvedMethodName::set_vmholder(oop resolved_method, oop holder) {
+ assert(is_instance(resolved_method), "wrong type");
+ resolved_method->obj_field_put(_vmholder_offset, holder);
+}
+
oop java_lang_invoke_ResolvedMethodName::find_resolved_method(const methodHandle& m, TRAPS) {
+ const Method* method = m();
+
// lookup ResolvedMethod oop in the table, or create a new one and intern it
- oop resolved_method = ResolvedMethodTable::find_method(m());
- if (resolved_method == NULL) {
- InstanceKlass* k = SystemDictionary::ResolvedMethodName_klass();
- if (!k->is_initialized()) {
- k->initialize(CHECK_NULL);
- }
- oop new_resolved_method = k->allocate_instance(CHECK_NULL);
- new_resolved_method->address_field_put(_vmtarget_offset, (address)m());
- // Add a reference to the loader (actually mirror because unsafe anonymous classes will not have
- // distinct loaders) to ensure the metadata is kept alive.
- // This mirror may be different than the one in clazz field.
- new_resolved_method->obj_field_put(_vmholder_offset, m->method_holder()->java_mirror());
- resolved_method = ResolvedMethodTable::add_method(m, Handle(THREAD, new_resolved_method));
+ oop resolved_method = ResolvedMethodTable::find_method(method);
+ if (resolved_method != NULL) {
+ return resolved_method;
+ }
+
+ InstanceKlass* k = SystemDictionary::ResolvedMethodName_klass();
+ if (!k->is_initialized()) {
+ k->initialize(CHECK_NULL);
}
- return resolved_method;
+
+ oop new_resolved_method = k->allocate_instance(CHECK_NULL);
+
+ NoSafepointVerifier nsv;
+
+ if (method->is_old()) {
+ method = (method->is_deleted()) ? Universe::throw_no_such_method_error() :
+ method->get_new_method();
+ }
+
+ InstanceKlass* holder = method->method_holder();
+
+ set_vmtarget(new_resolved_method, const_cast<Method*>(method));
+ // Add a reference to the loader (actually mirror because unsafe anonymous classes will not have
+ // distinct loaders) to ensure the metadata is kept alive.
+ // This mirror may be different than the one in clazz field.
+ set_vmholder(new_resolved_method, holder->java_mirror());
+
+ // Set flag in class to indicate this InstanceKlass has entries in the table
+ // to avoid walking table during redefinition if none of the redefined classes
+ // have any membernames in the table.
+ holder->set_has_resolved_methods();
+
+ return ResolvedMethodTable::add_method(method, Handle(THREAD, new_resolved_method));
}
oop java_lang_invoke_LambdaForm::vmentry(oop lform) {
--- a/src/hotspot/share/classfile/javaClasses.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/classfile/javaClasses.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -94,6 +94,7 @@
private:
static int value_offset;
static int hash_offset;
+ static int hashIsZero_offset;
static int coder_offset;
static bool initialized;
@@ -132,6 +133,10 @@
assert(initialized && (hash_offset > 0), "Must be initialized");
return hash_offset;
}
+ static int hashIsZero_offset_in_bytes() {
+ assert(initialized && (hashIsZero_offset > 0), "Must be initialized");
+ return hashIsZero_offset;
+ }
static int coder_offset_in_bytes() {
assert(initialized && (coder_offset > 0), "Must be initialized");
return coder_offset;
@@ -139,12 +144,11 @@
static inline void set_value_raw(oop string, typeArrayOop buffer);
static inline void set_value(oop string, typeArrayOop buffer);
- static inline void set_hash(oop string, unsigned int hash);
// Accessors
static inline typeArrayOop value(oop java_string);
static inline typeArrayOop value_no_keepalive(oop java_string);
- static inline unsigned int hash(oop java_string);
+ static inline bool hash_is_set(oop string);
static inline bool is_latin1(oop java_string);
static inline int length(oop java_string);
static inline int length(oop java_string, typeArrayOop string_value);
@@ -1059,6 +1063,8 @@
static Method* vmtarget(oop resolved_method);
static void set_vmtarget(oop resolved_method, Method* method);
+ static void set_vmholder(oop resolved_method, oop holder);
+
// find or create resolved member name
static oop find_resolved_method(const methodHandle& m, TRAPS);
--- a/src/hotspot/share/classfile/javaClasses.inline.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/classfile/javaClasses.inline.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -45,9 +45,9 @@
string->obj_field_put(value_offset, (oop)buffer);
}
-void java_lang_String::set_hash(oop string, unsigned int hash) {
- assert(initialized && (hash_offset > 0), "Must be initialized");
- string->int_field_put(hash_offset, hash);
+bool java_lang_String::hash_is_set(oop java_string) {
+ assert(initialized && (hash_offset > 0) && (hashIsZero_offset > 0), "Must be initialized");
+ return java_string->int_field(hash_offset) != 0 || java_string->bool_field(hashIsZero_offset) != 0;
}
// Accessors
@@ -71,12 +71,6 @@
return (typeArrayOop) java_string->obj_field_access<AS_NO_KEEPALIVE>(value_offset);
}
-unsigned int java_lang_String::hash(oop java_string) {
- assert(initialized && (hash_offset > 0), "Must be initialized");
- assert(is_instance(java_string), "must be java_string");
- return java_string->int_field(hash_offset);
-}
-
bool java_lang_String::is_latin1(oop java_string) {
assert(initialized && (coder_offset > 0), "Must be initialized");
assert(is_instance(java_string), "must be java_string");
--- a/src/hotspot/share/classfile/stringTable.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/classfile/stringTable.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -761,8 +761,6 @@
return true;
}
unsigned int hash = java_lang_String::hash_code(s);
-
- java_lang_String::set_hash(s, hash);
oop new_s = StringTable::create_archived_string(s, Thread::current());
if (new_s == NULL) {
return true;
--- a/src/hotspot/share/classfile/systemDictionary.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/classfile/systemDictionary.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -68,7 +68,6 @@
#include "oops/symbol.hpp"
#include "oops/typeArrayKlass.hpp"
#include "prims/jvmtiExport.hpp"
-#include "prims/resolvedMethodTable.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp"
#include "runtime/biasedLocking.hpp"
@@ -1836,8 +1835,6 @@
}
GCTraceTime(Debug, gc, phases) t("Trigger cleanups", gc_timer);
- // Trigger cleaning the ResolvedMethodTable even if no unloading occurred.
- ResolvedMethodTable::trigger_cleanup();
if (unloading_occurred) {
SymbolTable::trigger_cleanup();
--- a/src/hotspot/share/compiler/compileBroker.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/compiler/compileBroker.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -135,11 +135,6 @@
volatile jint CompileBroker::_compilation_id = 0;
volatile jint CompileBroker::_osr_compilation_id = 0;
-// Debugging information
-int CompileBroker::_last_compile_type = no_compile;
-int CompileBroker::_last_compile_level = CompLevel_none;
-char CompileBroker::_last_method_compiled[CompileBroker::name_buffer_length];
-
// Performance counters
PerfCounter* CompileBroker::_perf_total_compilation = NULL;
PerfCounter* CompileBroker::_perf_osr_compilation = NULL;
@@ -577,8 +572,6 @@
//
// Initialize the Compilation object
void CompileBroker::compilation_init_phase1(TRAPS) {
- _last_method_compiled[0] = '\0';
-
// No need to initialize compilation system if we do not use it.
if (!UseCompiler) {
return;
@@ -2032,8 +2025,10 @@
// Look up matching directives
directive = DirectivesStack::getMatchingDirective(method, comp);
- // Save information about this method in case of failure.
- set_last_compile(thread, method, is_osr, task_level);
+ // Update compile information when using perfdata.
+ if (UsePerfData) {
+ update_compile_perf_data(thread, method, is_osr);
+ }
DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, compiler_name(task_level));
}
@@ -2264,58 +2259,49 @@
}
// ------------------------------------------------------------------
-// CompileBroker::set_last_compile
+// CompileBroker::update_compile_perf_data
//
// Record this compilation for debugging purposes.
-void CompileBroker::set_last_compile(CompilerThread* thread, const methodHandle& method, bool is_osr, int comp_level) {
+void CompileBroker::update_compile_perf_data(CompilerThread* thread, const methodHandle& method, bool is_osr) {
ResourceMark rm;
char* method_name = method->name()->as_C_string();
- strncpy(_last_method_compiled, method_name, CompileBroker::name_buffer_length);
- _last_method_compiled[CompileBroker::name_buffer_length - 1] = '\0'; // ensure null terminated
char current_method[CompilerCounters::cmname_buffer_length];
size_t maxLen = CompilerCounters::cmname_buffer_length;
- if (UsePerfData) {
- const char* class_name = method->method_holder()->name()->as_C_string();
-
- size_t s1len = strlen(class_name);
- size_t s2len = strlen(method_name);
+ const char* class_name = method->method_holder()->name()->as_C_string();
- // check if we need to truncate the string
- if (s1len + s2len + 2 > maxLen) {
+ size_t s1len = strlen(class_name);
+ size_t s2len = strlen(method_name);
- // the strategy is to lop off the leading characters of the
- // class name and the trailing characters of the method name.
+ // check if we need to truncate the string
+ if (s1len + s2len + 2 > maxLen) {
- if (s2len + 2 > maxLen) {
- // lop of the entire class name string, let snprintf handle
- // truncation of the method name.
- class_name += s1len; // null string
- }
- else {
- // lop off the extra characters from the front of the class name
- class_name += ((s1len + s2len + 2) - maxLen);
- }
+ // the strategy is to lop off the leading characters of the
+ // class name and the trailing characters of the method name.
+
+ if (s2len + 2 > maxLen) {
+ // lop of the entire class name string, let snprintf handle
+ // truncation of the method name.
+ class_name += s1len; // null string
}
-
- jio_snprintf(current_method, maxLen, "%s %s", class_name, method_name);
+ else {
+ // lop off the extra characters from the front of the class name
+ class_name += ((s1len + s2len + 2) - maxLen);
+ }
}
- if (CICountOSR && is_osr) {
- _last_compile_type = osr_compile;
- } else {
- _last_compile_type = normal_compile;
- }
- _last_compile_level = comp_level;
+ jio_snprintf(current_method, maxLen, "%s %s", class_name, method_name);
- if (UsePerfData) {
- CompilerCounters* counters = thread->counters();
- counters->set_current_method(current_method);
- counters->set_compile_type((jlong)_last_compile_type);
+ int last_compile_type = normal_compile;
+ if (CICountOSR && is_osr) {
+ last_compile_type = osr_compile;
}
+
+ CompilerCounters* counters = thread->counters();
+ counters->set_current_method(current_method);
+ counters->set_compile_type((jlong) last_compile_type);
}
-
// ------------------------------------------------------------------
// CompileBroker::push_jni_handle_block
//
@@ -2618,21 +2604,6 @@
tty->print_cr(" nmethod total size : %8d bytes", nmethods_size);
}
-// Debugging output for failure
-void CompileBroker::print_last_compile() {
- if (_last_compile_level != CompLevel_none &&
- compiler(_last_compile_level) != NULL &&
- _last_compile_type != no_compile) {
- if (_last_compile_type == osr_compile) {
- tty->print_cr("Last parse: [osr]%d+++(%d) %s",
- _osr_compilation_id, _last_compile_level, _last_method_compiled);
- } else {
- tty->print_cr("Last parse: %d+++(%d) %s",
- _compilation_id, _last_compile_level, _last_method_compiled);
- }
- }
-}
-
// Print general/accumulated JIT information.
void CompileBroker::print_info(outputStream *out) {
if (out == NULL) out = tty;
--- a/src/hotspot/share/compiler/compileBroker.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/compiler/compileBroker.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -173,10 +173,6 @@
static volatile jint _compilation_id;
static volatile jint _osr_compilation_id;
- static int _last_compile_type;
- static int _last_compile_level;
- static char _last_method_compiled[name_buffer_length];
-
static CompileQueue* _c2_compile_queue;
static CompileQueue* _c1_compile_queue;
@@ -254,7 +250,8 @@
static void invoke_compiler_on_method(CompileTask* task);
static void post_compile(CompilerThread* thread, CompileTask* task, bool success, ciEnv* ci_env,
int compilable, const char* failure_reason);
- static void set_last_compile(CompilerThread *thread, const methodHandle& method, bool is_osr, int comp_level);
+ static void update_compile_perf_data(CompilerThread *thread, const methodHandle& method, bool is_osr);
+
static void push_jni_handle_block();
static void pop_jni_handle_block();
static void collect_statistics(CompilerThread* thread, elapsedTimer time, CompileTask* task);
@@ -382,9 +379,6 @@
// Print a detailed accounting of compilation time
static void print_times(bool per_compiler = true, bool aggregate = true);
- // Debugging output for failure
- static void print_last_compile();
-
// compiler name for debugging
static const char* compiler_name(int comp_level);
--- a/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -351,19 +351,14 @@
unsigned int hash = 0;
if (use_java_hash()) {
- // Get hash code from cache
- hash = java_lang_String::hash(java_string);
- }
-
- if (hash == 0) {
+ if (!java_lang_String::hash_is_set(java_string)) {
+ stat->inc_hashed();
+ }
+ hash = java_lang_String::hash_code(java_string);
+ } else {
// Compute hash
hash = hash_code(value, latin1);
stat->inc_hashed();
-
- if (use_java_hash() && hash != 0) {
- // Store hash code in cache
- java_lang_String::set_hash(java_string, hash);
- }
}
typeArrayOop existing_value = lookup_or_add(value, latin1, hash);
--- a/src/hotspot/share/gc/shared/weakProcessor.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/shared/weakProcessor.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -31,22 +31,33 @@
#include "gc/shared/weakProcessorPhaseTimes.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/iterator.hpp"
+#include "prims/resolvedMethodTable.hpp"
#include "runtime/globals.hpp"
#include "utilities/macros.hpp"
+template <typename Container>
+class OopsDoAndReportCounts {
+public:
+ void operator()(BoolObjectClosure* is_alive, OopClosure* keep_alive, WeakProcessorPhase phase) {
+ Container::reset_dead_counter();
+
+ CountingSkippedIsAliveClosure<BoolObjectClosure, OopClosure> cl(is_alive, keep_alive);
+ WeakProcessorPhases::oop_storage(phase)->oops_do(&cl);
+
+ Container::inc_dead_counter(cl.num_dead() + cl.num_skipped());
+ Container::finish_dead_counter();
+ }
+};
+
void WeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive) {
FOR_EACH_WEAK_PROCESSOR_PHASE(phase) {
if (WeakProcessorPhases::is_serial(phase)) {
WeakProcessorPhases::processor(phase)(is_alive, keep_alive);
} else {
if (WeakProcessorPhases::is_stringtable(phase)) {
- StringTable::reset_dead_counter();
-
- CountingSkippedIsAliveClosure<BoolObjectClosure, OopClosure> cl(is_alive, keep_alive);
- WeakProcessorPhases::oop_storage(phase)->oops_do(&cl);
-
- StringTable::inc_dead_counter(cl.num_dead() + cl.num_skipped());
- StringTable::finish_dead_counter();
+ OopsDoAndReportCounts<StringTable>()(is_alive, keep_alive, phase);
+ } else if (WeakProcessorPhases::is_resolved_method_table(phase)){
+ OopsDoAndReportCounts<ResolvedMethodTable>()(is_alive, keep_alive, phase);
} else {
WeakProcessorPhases::oop_storage(phase)->weak_oops_do(is_alive, keep_alive);
}
@@ -104,6 +115,7 @@
new (states++) StorageState(storage, _nworkers);
}
StringTable::reset_dead_counter();
+ ResolvedMethodTable::reset_dead_counter();
}
WeakProcessor::Task::Task(uint nworkers) :
@@ -134,6 +146,7 @@
FREE_C_HEAP_ARRAY(StorageState, _storage_states);
}
StringTable::finish_dead_counter();
+ ResolvedMethodTable::finish_dead_counter();
}
void WeakProcessor::GangTask::work(uint worker_id) {
--- a/src/hotspot/share/gc/shared/weakProcessor.inline.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/shared/weakProcessor.inline.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -32,6 +32,7 @@
#include "gc/shared/weakProcessorPhases.hpp"
#include "gc/shared/weakProcessorPhaseTimes.hpp"
#include "gc/shared/workgroup.hpp"
+#include "prims/resolvedMethodTable.hpp"
#include "utilities/debug.hpp"
class BoolObjectClosure;
@@ -115,6 +116,9 @@
if (WeakProcessorPhases::is_stringtable(phase)) {
StringTable::inc_dead_counter(cl.num_dead() + cl.num_skipped());
}
+ if (WeakProcessorPhases::is_resolved_method_table(phase)) {
+ ResolvedMethodTable::inc_dead_counter(cl.num_dead() + cl.num_skipped());
+ }
}
}
--- a/src/hotspot/share/gc/shared/weakProcessorPhases.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/shared/weakProcessorPhases.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -26,6 +26,7 @@
#include "classfile/stringTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "gc/shared/weakProcessorPhases.hpp"
+#include "prims/resolvedMethodTable.hpp"
#include "runtime/jniHandles.hpp"
#include "utilities/debug.hpp"
#include "utilities/macros.hpp"
@@ -80,6 +81,7 @@
JFR_ONLY(case jfr: return "JFR weak processing";)
case jni: return "JNI weak processing";
case stringtable: return "StringTable weak processing";
+ case resolved_method_table: return "ResolvedMethodTable weak processing";
case vm: return "VM weak processing";
default:
ShouldNotReachHere();
@@ -101,6 +103,7 @@
switch (phase) {
case jni: return JNIHandles::weak_global_handles();
case stringtable: return StringTable::weak_storage();
+ case resolved_method_table: return ResolvedMethodTable::weak_storage();
case vm: return SystemDictionary::vm_weak_oop_storage();
default:
ShouldNotReachHere();
@@ -111,3 +114,7 @@
bool WeakProcessorPhases::is_stringtable(Phase phase) {
return phase == stringtable;
}
+
+bool WeakProcessorPhases::is_resolved_method_table(Phase phase) {
+ return phase == resolved_method_table;
+}
--- a/src/hotspot/share/gc/shared/weakProcessorPhases.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/shared/weakProcessorPhases.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -45,6 +45,7 @@
// OopStorage phases.
jni,
stringtable,
+ resolved_method_table,
vm
};
@@ -68,6 +69,7 @@
static OopStorage* oop_storage(Phase phase); // Precondition: is_oop_storage(phase)
static bool is_stringtable(Phase phase);
+ static bool is_resolved_method_table(Phase phase);
};
typedef WeakProcessorPhases::Phase WeakProcessorPhase;
--- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahTraversalHeuristics.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahTraversalHeuristics.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -41,13 +41,6 @@
FLAG_SET_DEFAULT(ShenandoahKeepAliveBarrier, false);
FLAG_SET_DEFAULT(ShenandoahAllowMixedAllocs, false);
- SHENANDOAH_ERGO_OVERRIDE_DEFAULT(ShenandoahRefProcFrequency, 1);
-
- // Adjust class unloading settings only if globally enabled.
- if (ClassUnloadingWithConcurrentMark) {
- SHENANDOAH_ERGO_OVERRIDE_DEFAULT(ShenandoahUnloadClassesFrequency, 1);
- }
-
SHENANDOAH_ERGO_ENABLE_FLAG(ExplicitGCInvokesConcurrent);
SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahImplicitGCInvokesConcurrent);
--- a/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -196,6 +196,10 @@
} else {
_rp->process_all_roots(&roots_cl, &cld_cl, &code_cl, NULL, worker_id);
}
+ if (ShenandoahStringDedup::is_enabled()) {
+ AlwaysTrueClosure is_alive;
+ ShenandoahStringDedup::parallel_oops_do(&is_alive, &roots_cl, worker_id);
+ }
}
}
};
@@ -595,11 +599,10 @@
}
if (!_heap->cancelled_gc()) {
+ fixup_roots();
if (_heap->unload_classes()) {
_heap->unload_classes_and_cleanup_tables(false);
}
-
- fixup_roots();
}
if (!_heap->cancelled_gc()) {
@@ -769,29 +772,6 @@
void do_oop(oop* p) { do_oop_work(p); }
};
-class ShenandoahTraversalWeakUpdateClosure : public OopClosure {
-private:
- template <class T>
- inline void do_oop_work(T* p) {
- // Cannot call maybe_update_with_forwarded, because on traversal-degen
- // path the collection set is already dropped. Instead, do the unguarded store.
- // TODO: This can be fixed after degen-traversal stops dropping cset.
- T o = RawAccess<>::oop_load(p);
- if (!CompressedOops::is_null(o)) {
- oop obj = CompressedOops::decode_not_null(o);
- obj = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
- shenandoah_assert_marked(p, obj);
- RawAccess<IS_NOT_NULL>::oop_store(p, obj);
- }
- }
-
-public:
- ShenandoahTraversalWeakUpdateClosure() {}
-
- void do_oop(narrowOop* p) { do_oop_work(p); }
- void do_oop(oop* p) { do_oop_work(p); }
-};
-
class ShenandoahTraversalKeepAliveUpdateDegenClosure : public OopClosure {
private:
ShenandoahObjToScanQueue* _queue;
@@ -1104,16 +1084,6 @@
&pt);
}
- {
- ShenandoahGCPhase phase(phase_process);
- ShenandoahTerminationTracker termination(ShenandoahPhaseTimings::weakrefs_termination);
-
- // Process leftover weak oops (using parallel version)
- ShenandoahTraversalWeakUpdateClosure cl;
- WeakProcessor::weak_oops_do(workers, &is_alive, &cl, 1);
-
- pt.print_all_references();
-
- assert(task_queues()->is_empty() || _heap->cancelled_gc(), "Should be empty");
- }
+ pt.print_all_references();
+ assert(task_queues()->is_empty() || _heap->cancelled_gc(), "Should be empty");
}
--- a/src/hotspot/share/gc/z/zBarrier.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/z/zBarrier.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -123,7 +123,7 @@
}
void ZBarrier::load_barrier_on_oop_fields(oop o) {
- assert(ZOop::is_good(o), "Should be good");
+ assert(ZAddress::is_good(ZOop::to_address(o)), "Should be good");
ZLoadBarrierOopClosure cl;
o->oop_iterate(&cl);
}
--- a/src/hotspot/share/gc/z/zBarrier.inline.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/z/zBarrier.inline.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -37,7 +37,7 @@
retry:
// Fast path
if (fast_path(addr)) {
- return ZOop::to_oop(addr);
+ return ZOop::from_address(addr);
}
// Slow path
@@ -56,7 +56,7 @@
}
}
- return ZOop::to_oop(good_addr);
+ return ZOop::from_address(good_addr);
}
template <ZBarrierFastPath fast_path, ZBarrierSlowPath slow_path>
@@ -67,7 +67,7 @@
if (fast_path(addr)) {
// Return the good address instead of the weak good address
// to ensure that the currently active heap view is used.
- return ZOop::to_oop(ZAddress::good_or_null(addr));
+ return ZOop::from_address(ZAddress::good_or_null(addr));
}
// Slow path
@@ -95,7 +95,7 @@
}
}
- return ZOop::to_oop(good_addr);
+ return ZOop::from_address(good_addr);
}
template <ZBarrierFastPath fast_path, ZBarrierSlowPath slow_path>
@@ -117,7 +117,7 @@
// to heal the same root if it is aligned, since they would always heal
// the root in the same way and it does not matter in which order it
// happens. For misaligned oops, there needs to be mutual exclusion.
- *p = ZOop::to_oop(good_addr);
+ *p = ZOop::from_address(good_addr);
}
inline bool ZBarrier::is_null_fast_path(uintptr_t addr) {
--- a/src/hotspot/share/gc/z/zForwarding.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/z/zForwarding.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -69,6 +69,11 @@
// Check for duplicates
for (ZForwardingCursor j = i + 1; j < _entries.length(); j++) {
const ZForwardingEntry other = at(&j);
+ if (!other.populated()) {
+ // Skip empty entries
+ continue;
+ }
+
guarantee(entry.from_index() != other.from_index(), "Duplicate from");
guarantee(entry.to_offset() != other.to_offset(), "Duplicate to");
}
--- a/src/hotspot/share/gc/z/zHeap.inline.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/z/zHeap.inline.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -135,7 +135,7 @@
}
inline bool ZHeap::is_oop(oop object) const {
- return ZOop::is_good(object);
+ return ZAddress::is_good(ZOop::to_address(object));
}
#endif // SHARE_GC_Z_ZHEAP_INLINE_HPP
--- a/src/hotspot/share/gc/z/zLiveMap.inline.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/z/zLiveMap.inline.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -144,7 +144,7 @@
const uintptr_t addr = page_start + ((index / 2) << page_object_alignment_shift);
// Apply closure
- cl->do_object(ZOop::to_oop(addr));
+ cl->do_object(ZOop::from_address(addr));
// Find next bit after this object
const size_t size = ZUtils::object_size(addr);
--- a/src/hotspot/share/gc/z/zMark.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/z/zMark.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -200,7 +200,7 @@
}
bool ZMark::is_array(uintptr_t addr) const {
- return ZOop::to_oop(addr)->is_objArray();
+ return ZOop::from_address(addr)->is_objArray();
}
void ZMark::push_partial_array(uintptr_t addr, size_t size, bool finalizable) {
@@ -347,9 +347,9 @@
}
if (is_array(addr)) {
- follow_array_object(objArrayOop(ZOop::to_oop(addr)), finalizable);
+ follow_array_object(objArrayOop(ZOop::from_address(addr)), finalizable);
} else {
- follow_object(ZOop::to_oop(addr), finalizable);
+ follow_object(ZOop::from_address(addr), finalizable);
}
}
--- a/src/hotspot/share/gc/z/zOop.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/z/zOop.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* 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,13 +29,8 @@
class ZOop : public AllStatic {
public:
- static oop to_oop(uintptr_t value);
+ static oop from_address(uintptr_t addr);
static uintptr_t to_address(oop o);
-
- static bool is_good(oop o);
- static bool is_finalizable_good(oop o);
-
- static oop good(oop);
};
#endif // SHARE_GC_Z_ZOOP_HPP
--- a/src/hotspot/share/gc/z/zOop.inline.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/z/zOop.inline.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* 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,28 +24,14 @@
#ifndef SHARE_GC_Z_ZOOP_INLINE_HPP
#define SHARE_GC_Z_ZOOP_INLINE_HPP
-#include "gc/z/zAddress.inline.hpp"
#include "gc/z/zOop.hpp"
-#include "oops/oopsHierarchy.hpp"
-inline oop ZOop::to_oop(uintptr_t value) {
- return cast_to_oop(value);
+inline oop ZOop::from_address(uintptr_t addr) {
+ return cast_to_oop(addr);
}
inline uintptr_t ZOop::to_address(oop o) {
return cast_from_oop<uintptr_t>(o);
}
-inline bool ZOop::is_good(oop o) {
- return ZAddress::is_good(to_address(o));
-}
-
-inline bool ZOop::is_finalizable_good(oop o) {
- return ZAddress::is_finalizable_good(to_address(o));
-}
-
-inline oop ZOop::good(oop o) {
- return to_oop(ZAddress::good(to_address(o)));
-}
-
#endif // SHARE_GC_Z_ZOOP_INLINE_HPP
--- a/src/hotspot/share/gc/z/zOopClosures.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/z/zOopClosures.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* 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,12 +39,14 @@
const oop o = RawAccess<>::oop_load(p);
if (o != NULL) {
- guarantee(ZOop::is_good(o) || ZOop::is_finalizable_good(o),
+ const uintptr_t addr = ZOop::to_address(o);
+ const uintptr_t good_addr = ZAddress::good(addr);
+ guarantee(ZAddress::is_good(addr) || ZAddress::is_finalizable_good(addr),
"Bad oop " PTR_FORMAT " found at " PTR_FORMAT ", expected " PTR_FORMAT,
- p2i(o), p2i(p), p2i(ZOop::good(o)));
- guarantee(oopDesc::is_oop(ZOop::good(o)),
+ addr, p2i(p), good_addr);
+ guarantee(oopDesc::is_oop(ZOop::from_address(good_addr)),
"Bad object " PTR_FORMAT " found at " PTR_FORMAT,
- p2i(o), p2i(p));
+ addr, p2i(p));
}
}
--- a/src/hotspot/share/gc/z/zRootsIterator.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/z/zRootsIterator.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -41,6 +41,7 @@
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "prims/jvmtiExport.hpp"
+#include "prims/resolvedMethodTable.hpp"
#include "runtime/atomic.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/thread.hpp"
@@ -80,6 +81,7 @@
static const ZStatSubPhase ZSubPhaseConcurrentWeakRootsVMWeakHandles("Concurrent Weak Roots VMWeakHandles");
static const ZStatSubPhase ZSubPhaseConcurrentWeakRootsJNIWeakHandles("Concurrent Weak Roots JNIWeakHandles");
static const ZStatSubPhase ZSubPhaseConcurrentWeakRootsStringTable("Concurrent Weak Roots StringTable");
+static const ZStatSubPhase ZSubPhaseConcurrentWeakRootsResolvedMethodTable("Concurrent Weak Roots ResolvedMethodTable");
template <typename T, void (T::*F)(ZRootsIteratorClosure*)>
ZSerialOopsDo<T, F>::ZSerialOopsDo(T* iter) :
@@ -341,14 +343,18 @@
_vm_weak_handles_iter(SystemDictionary::vm_weak_oop_storage()),
_jni_weak_handles_iter(JNIHandles::weak_global_handles()),
_string_table_iter(StringTable::weak_storage()),
+ _resolved_method_table_iter(ResolvedMethodTable::weak_storage()),
_vm_weak_handles(this),
_jni_weak_handles(this),
- _string_table(this) {
+ _string_table(this),
+ _resolved_method_table(this) {
StringTable::reset_dead_counter();
+ ResolvedMethodTable::reset_dead_counter();
}
ZConcurrentWeakRootsIterator::~ZConcurrentWeakRootsIterator() {
StringTable::finish_dead_counter();
+ ResolvedMethodTable::finish_dead_counter();
}
void ZConcurrentWeakRootsIterator::do_vm_weak_handles(ZRootsIteratorClosure* cl) {
@@ -361,18 +367,19 @@
_jni_weak_handles_iter.oops_do(cl);
}
-class ZStringTableDeadCounterClosure : public ZRootsIteratorClosure {
+template <class Container>
+class ZDeadCounterClosure : public ZRootsIteratorClosure {
private:
ZRootsIteratorClosure* const _cl;
size_t _ndead;
public:
- ZStringTableDeadCounterClosure(ZRootsIteratorClosure* cl) :
+ ZDeadCounterClosure(ZRootsIteratorClosure* cl) :
_cl(cl),
_ndead(0) {}
- ~ZStringTableDeadCounterClosure() {
- StringTable::inc_dead_counter(_ndead);
+ ~ZDeadCounterClosure() {
+ Container::inc_dead_counter(_ndead);
}
virtual void do_oop(oop* p) {
@@ -389,15 +396,22 @@
void ZConcurrentWeakRootsIterator::do_string_table(ZRootsIteratorClosure* cl) {
ZStatTimer timer(ZSubPhaseConcurrentWeakRootsStringTable);
- ZStringTableDeadCounterClosure counter_cl(cl);
+ ZDeadCounterClosure<StringTable> counter_cl(cl);
_string_table_iter.oops_do(&counter_cl);
}
+void ZConcurrentWeakRootsIterator::do_resolved_method_table(ZRootsIteratorClosure* cl) {
+ ZStatTimer timer(ZSubPhaseConcurrentWeakRootsResolvedMethodTable);
+ ZDeadCounterClosure<ResolvedMethodTable> counter_cl(cl);
+ _resolved_method_table_iter.oops_do(&counter_cl);
+}
+
void ZConcurrentWeakRootsIterator::oops_do(ZRootsIteratorClosure* cl) {
ZStatTimer timer(ZSubPhaseConcurrentWeakRoots);
_vm_weak_handles.oops_do(cl);
_jni_weak_handles.oops_do(cl);
_string_table.oops_do(cl);
+ _resolved_method_table.oops_do(cl);
}
ZThreadRootsIterator::ZThreadRootsIterator() :
--- a/src/hotspot/share/gc/z/zRootsIterator.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/z/zRootsIterator.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -149,14 +149,17 @@
ZOopStorageIterator _vm_weak_handles_iter;
ZOopStorageIterator _jni_weak_handles_iter;
ZOopStorageIterator _string_table_iter;
+ ZOopStorageIterator _resolved_method_table_iter;
void do_vm_weak_handles(ZRootsIteratorClosure* cl);
void do_jni_weak_handles(ZRootsIteratorClosure* cl);
void do_string_table(ZRootsIteratorClosure* cl);
+ void do_resolved_method_table(ZRootsIteratorClosure* cl);
- ZParallelOopsDo<ZConcurrentWeakRootsIterator, &ZConcurrentWeakRootsIterator::do_vm_weak_handles> _vm_weak_handles;
- ZParallelOopsDo<ZConcurrentWeakRootsIterator, &ZConcurrentWeakRootsIterator::do_jni_weak_handles> _jni_weak_handles;
- ZParallelOopsDo<ZConcurrentWeakRootsIterator, &ZConcurrentWeakRootsIterator::do_string_table> _string_table;
+ ZParallelOopsDo<ZConcurrentWeakRootsIterator, &ZConcurrentWeakRootsIterator::do_vm_weak_handles> _vm_weak_handles;
+ ZParallelOopsDo<ZConcurrentWeakRootsIterator, &ZConcurrentWeakRootsIterator::do_jni_weak_handles> _jni_weak_handles;
+ ZParallelOopsDo<ZConcurrentWeakRootsIterator, &ZConcurrentWeakRootsIterator::do_string_table> _string_table;
+ ZParallelOopsDo<ZConcurrentWeakRootsIterator, &ZConcurrentWeakRootsIterator::do_resolved_method_table> _resolved_method_table;
public:
ZConcurrentWeakRootsIterator();
--- a/src/hotspot/share/gc/z/zUtils.inline.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/gc/z/zUtils.inline.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -57,7 +57,7 @@
}
inline size_t ZUtils::object_size(uintptr_t addr) {
- return words_to_bytes(ZOop::to_oop(addr)->size());
+ return words_to_bytes(ZOop::from_address(addr)->size());
}
inline void ZUtils::object_copy(uintptr_t from, uintptr_t to, size_t size) {
--- a/src/hotspot/share/oops/weakHandle.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/oops/weakHandle.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -29,6 +29,7 @@
#include "oops/access.inline.hpp"
#include "oops/oop.hpp"
#include "oops/weakHandle.inline.hpp"
+#include "prims/resolvedMethodTable.hpp"
#include "utilities/debug.hpp"
#include "utilities/ostream.hpp"
@@ -40,6 +41,10 @@
return StringTable::weak_storage();
}
+template <> OopStorage* WeakHandle<vm_resolved_method_table_data>::get_storage() {
+ return ResolvedMethodTable::weak_storage();
+}
+
template <WeakHandleType T>
WeakHandle<T> WeakHandle<T>::create(Handle obj) {
assert(obj() != NULL, "no need to create weak null oop");
@@ -74,4 +79,4 @@
// Provide instantiation.
template class WeakHandle<vm_class_loader_data>;
template class WeakHandle<vm_string_table_data>;
-
+template class WeakHandle<vm_resolved_method_table_data>;
--- a/src/hotspot/share/oops/weakHandle.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/oops/weakHandle.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -39,7 +39,7 @@
// This is the vm version of jweak but has different GC lifetimes and policies,
// depending on the type.
-enum WeakHandleType { vm_class_loader_data, vm_string_table_data };
+enum WeakHandleType { vm_class_loader_data, vm_string_table_data, vm_resolved_method_table_data };
template <WeakHandleType T>
class WeakHandle {
@@ -64,6 +64,4 @@
void print_on(outputStream* st) const;
};
-typedef WeakHandle<vm_class_loader_data> ClassLoaderWeakHandle;
-
#endif // SHARE_OOPS_WEAKHANDLE_HPP
--- a/src/hotspot/share/prims/jni.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/prims/jni.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -3971,7 +3971,7 @@
#endif
// Since this is not a JVM_ENTRY we have to set the thread state manually before leaving.
- ThreadStateTransition::transition_and_fence(thread, _thread_in_vm, _thread_in_native);
+ ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_native);
} else {
// If create_vm exits because of a pending exception, exit with that
// exception. In the future when we figure out how to reclaim memory,
@@ -4073,7 +4073,7 @@
res = JNI_OK;
return res;
} else {
- ThreadStateTransition::transition_and_fence(thread, _thread_in_vm, _thread_in_native);
+ ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_native);
res = JNI_ERR;
return res;
}
@@ -4195,7 +4195,7 @@
// using ThreadStateTransition::transition, we do a callback to the safepoint code if
// needed.
- ThreadStateTransition::transition_and_fence(thread, _thread_in_vm, _thread_in_native);
+ ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_native);
// Perform any platform dependent FPU setup
os::setup_fpu();
--- a/src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -236,7 +236,7 @@
// Don't hold the lock over the notify or jmethodID creation
MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
current->get_and_cache_jmethod_id();
- JvmtiExport::post_compiled_method_load(current);
+ JvmtiExport::post_compiled_method_load(env, current);
}
return JVMTI_ERROR_NONE;
}
--- a/src/hotspot/share/prims/jvmtiExport.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/prims/jvmtiExport.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -2170,61 +2170,37 @@
JvmtiEnvIterator it;
for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
- if (env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_LOAD)) {
- if (env->phase() == JVMTI_PHASE_PRIMORDIAL) {
- continue;
- }
- EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD,
- ("[%s] class compile method load event sent %s.%s ",
- JvmtiTrace::safe_get_thread_name(thread),
- (nm->method() == NULL) ? "NULL" : nm->method()->klass_name()->as_C_string(),
- (nm->method() == NULL) ? "NULL" : nm->method()->name()->as_C_string()));
- ResourceMark rm(thread);
- HandleMark hm(thread);
-
- // Add inlining information
- jvmtiCompiledMethodLoadInlineRecord* inlinerecord = create_inline_record(nm);
- // Pass inlining information through the void pointer
- JvmtiCompiledMethodLoadEventMark jem(thread, nm, inlinerecord);
- JvmtiJavaThreadEventTransition jet(thread);
- jvmtiEventCompiledMethodLoad callback = env->callbacks()->CompiledMethodLoad;
- if (callback != NULL) {
- (*callback)(env->jvmti_external(), jem.jni_methodID(),
- jem.code_size(), jem.code_data(), jem.map_length(),
- jem.map(), jem.compile_info());
- }
- }
+ post_compiled_method_load(env, nm);
}
}
-
// post a COMPILED_METHOD_LOAD event for a given environment
-void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, const jmethodID method, const jint length,
- const void *code_begin, const jint map_length,
- const jvmtiAddrLocationMap* map)
-{
- if (env->phase() <= JVMTI_PHASE_PRIMORDIAL) {
+void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, nmethod *nm) {
+ if (env->phase() == JVMTI_PHASE_PRIMORDIAL || !env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_LOAD)) {
+ return;
+ }
+ jvmtiEventCompiledMethodLoad callback = env->callbacks()->CompiledMethodLoad;
+ if (callback == NULL) {
return;
}
JavaThread* thread = JavaThread::current();
- EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD,
- ("[%s] method compile load event triggered (by GenerateEvents)",
- JvmtiTrace::safe_get_thread_name(thread)));
- if (env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_LOAD)) {
-
- EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD,
- ("[%s] class compile method load event sent (by GenerateEvents), jmethodID=" PTR_FORMAT,
- JvmtiTrace::safe_get_thread_name(thread), p2i(method)));
-
- JvmtiEventMark jem(thread);
- JvmtiJavaThreadEventTransition jet(thread);
- jvmtiEventCompiledMethodLoad callback = env->callbacks()->CompiledMethodLoad;
- if (callback != NULL) {
- (*callback)(env->jvmti_external(), method,
- length, code_begin, map_length,
- map, NULL);
- }
- }
+
+ EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD,
+ ("[%s] method compile load event sent %s.%s ",
+ JvmtiTrace::safe_get_thread_name(thread),
+ (nm->method() == NULL) ? "NULL" : nm->method()->klass_name()->as_C_string(),
+ (nm->method() == NULL) ? "NULL" : nm->method()->name()->as_C_string()));
+ ResourceMark rm(thread);
+ HandleMark hm(thread);
+
+ // Add inlining information
+ jvmtiCompiledMethodLoadInlineRecord* inlinerecord = create_inline_record(nm);
+ // Pass inlining information through the void pointer
+ JvmtiCompiledMethodLoadEventMark jem(thread, nm, inlinerecord);
+ JvmtiJavaThreadEventTransition jet(thread);
+ (*callback)(env->jvmti_external(), jem.jni_methodID(),
+ jem.code_size(), jem.code_data(), jem.map_length(),
+ jem.map(), jem.compile_info());
}
void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) {
--- a/src/hotspot/share/prims/jvmtiExport.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/prims/jvmtiExport.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -165,9 +165,7 @@
// DynamicCodeGenerated events for a given environment.
friend class JvmtiCodeBlobEvents;
- static void post_compiled_method_load(JvmtiEnv* env, const jmethodID method, const jint length,
- const void *code_begin, const jint map_length,
- const jvmtiAddrLocationMap* map) NOT_JVMTI_RETURN;
+ static void post_compiled_method_load(JvmtiEnv* env, nmethod *nm) NOT_JVMTI_RETURN;
static void post_dynamic_code_generated(JvmtiEnv* env, const char *name, const void *code_begin,
const void *code_end) NOT_JVMTI_RETURN;
--- a/src/hotspot/share/prims/resolvedMethodTable.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/prims/resolvedMethodTable.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -24,223 +24,422 @@
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
+#include "gc/shared/oopStorage.inline.hpp"
#include "logging/log.hpp"
#include "memory/allocation.hpp"
#include "memory/resourceArea.hpp"
#include "oops/access.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/method.hpp"
-#include "oops/symbol.hpp"
#include "oops/weakHandle.inline.hpp"
#include "prims/resolvedMethodTable.hpp"
#include "runtime/handles.inline.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/safepointVerifiers.hpp"
-#include "utilities/hashtable.inline.hpp"
+#include "runtime/timerTrace.hpp"
+#include "utilities/concurrentHashTable.inline.hpp"
+#include "utilities/concurrentHashTableTasks.inline.hpp"
#include "utilities/macros.hpp"
-
-oop ResolvedMethodEntry::object() {
- return literal().resolve();
-}
-
-oop ResolvedMethodEntry::object_no_keepalive() {
- // The AS_NO_KEEPALIVE peeks at the oop without keeping it alive.
- // This is dangerous in general but is okay if the loaded oop does
- // not leak out past a thread transition where a safepoint can happen.
- // A subsequent oop_load without AS_NO_KEEPALIVE (the object() accessor)
- // keeps the oop alive before doing so.
- return literal().peek();
-}
-
-ResolvedMethodTable::ResolvedMethodTable()
- : Hashtable<ClassLoaderWeakHandle, mtClass>(_table_size, sizeof(ResolvedMethodEntry)) { }
+// 2^24 is max size
+static const size_t END_SIZE = 24;
+// If a chain gets to 32 something might be wrong
+static const size_t GROW_HINT = 32;
-oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method* method) {
- assert_locked_or_safepoint(ResolvedMethodTable_lock);
- for (ResolvedMethodEntry* p = bucket(index); p != NULL; p = p->next()) {
- if (p->hash() == hash) {
-
- // Peek the object to check if it is the right target.
- oop target = p->object_no_keepalive();
+static const size_t ResolvedMethodTableSizeLog = 10;
- // The method is in the table as a target already
- if (target != NULL && java_lang_invoke_ResolvedMethodName::vmtarget(target) == method) {
- ResourceMark rm;
- log_debug(membername, table) ("ResolvedMethod entry found for %s index %d",
- method->name_and_sig_as_C_string(), index);
- // The object() accessor makes sure the target object is kept alive before
- // leaking out.
- return p->object();
- }
- }
- }
- return NULL;
-}
-
-unsigned int ResolvedMethodTable::compute_hash(Method* method) {
+unsigned int method_hash(const Method* method) {
unsigned int name_hash = method->name()->identity_hash();
unsigned int signature_hash = method->signature()->identity_hash();
return name_hash ^ signature_hash;
}
+class ResolvedMethodTableConfig : public ResolvedMethodTableHash::BaseConfig {
+ private:
+ public:
+ static uintx get_hash(WeakHandle<vm_resolved_method_table_data> const& value,
+ bool* is_dead) {
+ EXCEPTION_MARK;
+ oop val_oop = value.peek();
+ if (val_oop == NULL) {
+ *is_dead = true;
+ return 0;
+ }
+ *is_dead = false;
+ Method* method = java_lang_invoke_ResolvedMethodName::vmtarget(val_oop);
+ return method_hash(method);
+ }
-oop ResolvedMethodTable::lookup(Method* method) {
- unsigned int hash = compute_hash(method);
- int index = hash_to_index(hash);
- return lookup(index, hash, method);
+ // We use default allocation/deallocation but counted
+ static void* allocate_node(size_t size, WeakHandle<vm_resolved_method_table_data> const& value) {
+ ResolvedMethodTable::item_added();
+ return ResolvedMethodTableHash::BaseConfig::allocate_node(size, value);
+ }
+ static void free_node(void* memory, WeakHandle<vm_resolved_method_table_data> const& value) {
+ value.release();
+ ResolvedMethodTableHash::BaseConfig::free_node(memory, value);
+ ResolvedMethodTable::item_removed();
+ }
+};
+
+ResolvedMethodTableHash* ResolvedMethodTable::_local_table = NULL;
+size_t ResolvedMethodTable::_current_size = (size_t)1 << ResolvedMethodTableSizeLog;
+
+OopStorage* ResolvedMethodTable::_weak_handles = NULL;
+
+volatile bool ResolvedMethodTable::_has_work = false;
+volatile size_t ResolvedMethodTable::_items_count = 0;
+volatile size_t ResolvedMethodTable::_uncleaned_items_count = 0;
+
+void ResolvedMethodTable::create_table() {
+ _local_table = new ResolvedMethodTableHash(ResolvedMethodTableSizeLog, END_SIZE, GROW_HINT);
+ _weak_handles = new OopStorage("ResolvedMethodTable weak",
+ ResolvedMethodTableWeakAlloc_lock,
+ ResolvedMethodTableWeakActive_lock);
+ log_trace(membername, table)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")",
+ _current_size, ResolvedMethodTableSizeLog);
+}
+
+size_t ResolvedMethodTable::table_size() {
+ return (size_t)1 << _local_table->get_size_log2(Thread::current());
}
-oop ResolvedMethodTable::basic_add(Method* method, Handle rmethod_name) {
- assert_locked_or_safepoint(ResolvedMethodTable_lock);
+class ResolvedMethodTableLookup : StackObj {
+ private:
+ Thread* _thread;
+ uintx _hash;
+ const Method* _method;
+ Handle _found;
+
+ public:
+ ResolvedMethodTableLookup(Thread* thread, uintx hash, const Method* key)
+ : _thread(thread), _hash(hash), _method(key) {
+ }
+ uintx get_hash() const {
+ return _hash;
+ }
+ bool equals(WeakHandle<vm_resolved_method_table_data>* value, bool* is_dead) {
+ oop val_oop = value->peek();
+ if (val_oop == NULL) {
+ // dead oop, mark this hash dead for cleaning
+ *is_dead = true;
+ return false;
+ }
+ bool equals = _method == java_lang_invoke_ResolvedMethodName::vmtarget(val_oop);
+ if (!equals) {
+ return false;
+ }
+ // Need to resolve weak handle and Handleize through possible safepoint.
+ _found = Handle(_thread, value->resolve());
+ return true;
+ }
+};
+
- unsigned int hash = compute_hash(method);
- int index = hash_to_index(hash);
+class ResolvedMethodGet : public StackObj {
+ Thread* _thread;
+ const Method* _method;
+ Handle _return;
+public:
+ ResolvedMethodGet(Thread* thread, const Method* method) : _thread(thread), _method(method) {}
+ void operator()(WeakHandle<vm_resolved_method_table_data>* val) {
+ oop result = val->resolve();
+ assert(result != NULL, "Result should be reachable");
+ _return = Handle(_thread, result);
+ log_get();
+ }
+ oop get_res_oop() {
+ return _return();
+ }
+ void log_get() {
+ LogTarget(Trace, membername, table) log;
+ if (log.is_enabled()) {
+ ResourceMark rm;
+ log.print("ResolvedMethod entry found for %s",
+ _method->name_and_sig_as_C_string());
+ }
+ }
+};
+
+oop ResolvedMethodTable::find_method(const Method* method) {
+ Thread* thread = Thread::current();
- // One was added while aquiring the lock
- oop entry = lookup(index, hash, method);
- if (entry != NULL) {
- return entry;
+ ResolvedMethodTableLookup lookup(thread, method_hash(method), method);
+ ResolvedMethodGet rmg(thread, method);
+ _local_table->get(thread, lookup, rmg);
+
+ return rmg.get_res_oop();
+}
+
+static void log_insert(const Method* method) {
+ LogTarget(Debug, membername, table) log;
+ if (log.is_enabled()) {
+ ResourceMark rm;
+ log_debug(membername, table) ("ResolvedMethod entry added for %s",
+ method->name_and_sig_as_C_string());
+ }
+}
+
+oop ResolvedMethodTable::add_method(const Method* method, Handle rmethod_name) {
+ Thread* thread = Thread::current();
+
+ ResolvedMethodTableLookup lookup(thread, method_hash(method), method);
+ ResolvedMethodGet rmg(thread, method);
+
+ while (true) {
+ if (_local_table->get(thread, lookup, rmg)) {
+ return rmg.get_res_oop();
+ }
+ WeakHandle<vm_resolved_method_table_data> wh = WeakHandle<vm_resolved_method_table_data>::create(rmethod_name);
+ // The hash table takes ownership of the WeakHandle, even if it's not inserted.
+ if (_local_table->insert(thread, lookup, wh)) {
+ log_insert(method);
+ return wh.resolve();
+ }
}
- ClassLoaderWeakHandle w = ClassLoaderWeakHandle::create(rmethod_name);
- ResolvedMethodEntry* p = (ResolvedMethodEntry*) Hashtable<ClassLoaderWeakHandle, mtClass>::new_entry(hash, w);
- Hashtable<ClassLoaderWeakHandle, mtClass>::add_entry(index, p);
- ResourceMark rm;
- log_debug(membername, table) ("ResolvedMethod entry added for %s index %d",
- method->name_and_sig_as_C_string(), index);
return rmethod_name();
}
-ResolvedMethodTable* ResolvedMethodTable::_the_table = NULL;
+void ResolvedMethodTable::item_added() {
+ Atomic::inc(&_items_count);
+}
+
+void ResolvedMethodTable::item_removed() {
+ Atomic::dec(&_items_count);
+ log_trace(membername, table) ("ResolvedMethod entry removed");
+}
-oop ResolvedMethodTable::find_method(Method* method) {
- MutexLocker ml(ResolvedMethodTable_lock);
- oop entry = _the_table->lookup(method);
- return entry;
+bool ResolvedMethodTable::has_work() {
+ return _has_work;
+}
+
+OopStorage* ResolvedMethodTable::weak_storage() {
+ return _weak_handles;
+}
+
+double ResolvedMethodTable::get_load_factor() {
+ return (double)_items_count/_current_size;
+}
+
+double ResolvedMethodTable::get_dead_factor() {
+ return (double)_uncleaned_items_count/_current_size;
}
-oop ResolvedMethodTable::add_method(const methodHandle& m, Handle resolved_method_name) {
- MutexLocker ml(ResolvedMethodTable_lock);
- DEBUG_ONLY(NoSafepointVerifier nsv);
+static const double PREF_AVG_LIST_LEN = 2.0;
+// If we have as many dead items as 50% of the number of bucket
+static const double CLEAN_DEAD_HIGH_WATER_MARK = 0.5;
- Method* method = m();
- // Check if method has been redefined while taking out ResolvedMethodTable_lock, if so
- // use new method in the ResolvedMethodName. The old method won't be deallocated
- // yet because it's passed in as a Handle.
- if (method->is_old()) {
- method = (method->is_deleted()) ? Universe::throw_no_such_method_error() :
- method->get_new_method();
- java_lang_invoke_ResolvedMethodName::set_vmtarget(resolved_method_name(), method);
+void ResolvedMethodTable::check_concurrent_work() {
+ if (_has_work) {
+ return;
}
- // Set flag in class to indicate this InstanceKlass has entries in the table
- // to avoid walking table during redefinition if none of the redefined classes
- // have any membernames in the table.
- method->method_holder()->set_has_resolved_methods();
-
- return _the_table->basic_add(method, resolved_method_name);
+ double load_factor = get_load_factor();
+ double dead_factor = get_dead_factor();
+ // We should clean/resize if we have more dead than alive,
+ // more items than preferred load factor or
+ // more dead items than water mark.
+ if ((dead_factor > load_factor) ||
+ (load_factor > PREF_AVG_LIST_LEN) ||
+ (dead_factor > CLEAN_DEAD_HIGH_WATER_MARK)) {
+ log_debug(membername, table)("Concurrent work triggered, live factor: %g dead factor: %g",
+ load_factor, dead_factor);
+ trigger_concurrent_work();
+ }
}
-// Removing entries
-int ResolvedMethodTable::_total_oops_removed = 0;
-
-// There are no dead entries at start
-bool ResolvedMethodTable::_dead_entries = false;
-
-void ResolvedMethodTable::trigger_cleanup() {
+void ResolvedMethodTable::trigger_concurrent_work() {
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
- _dead_entries = true;
+ _has_work = true;
Service_lock->notify_all();
}
-// Serially invoke removed unused oops from the table.
-// This is done by the ServiceThread after being notified on class unloading
-void ResolvedMethodTable::unlink() {
- MutexLocker ml(ResolvedMethodTable_lock);
- int _oops_removed = 0;
- int _oops_counted = 0;
- for (int i = 0; i < _the_table->table_size(); ++i) {
- ResolvedMethodEntry** p = _the_table->bucket_addr(i);
- ResolvedMethodEntry* entry = _the_table->bucket(i);
- while (entry != NULL) {
- _oops_counted++;
- oop l = entry->object_no_keepalive();
- if (l != NULL) {
- p = entry->next_addr();
- } else {
- // Entry has been removed.
- _oops_removed++;
- if (log_is_enabled(Debug, membername, table)) {
- log_debug(membername, table) ("ResolvedMethod entry removed for index %d", i);
- }
- entry->literal().release();
- *p = entry->next();
- _the_table->free_entry(entry);
+void ResolvedMethodTable::do_concurrent_work(JavaThread* jt) {
+ _has_work = false;
+ double load_factor = get_load_factor();
+ log_debug(membername, table)("Concurrent work, live factor: %g", load_factor);
+ // We prefer growing, since that also removes dead items
+ if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) {
+ grow(jt);
+ } else {
+ clean_dead_entries(jt);
+ }
+}
+
+void ResolvedMethodTable::grow(JavaThread* jt) {
+ ResolvedMethodTableHash::GrowTask gt(_local_table);
+ if (!gt.prepare(jt)) {
+ return;
+ }
+ log_trace(membername, table)("Started to grow");
+ {
+ TraceTime timer("Grow", TRACETIME_LOG(Debug, membername, table, perf));
+ while (gt.do_task(jt)) {
+ gt.pause(jt);
+ {
+ ThreadBlockInVM tbivm(jt);
}
- // get next entry
- entry = (ResolvedMethodEntry*)HashtableEntry<ClassLoaderWeakHandle, mtClass>::make_ptr(*p);
+ gt.cont(jt);
+ }
+ }
+ gt.done(jt);
+ _current_size = table_size();
+ log_info(membername, table)("Grown to size:" SIZE_FORMAT, _current_size);
+}
+
+struct ResolvedMethodTableDoDelete : StackObj {
+ void operator()(WeakHandle<vm_resolved_method_table_data>* val) {
+ /* do nothing */
+ }
+};
+
+struct ResolvedMethodTableDeleteCheck : StackObj {
+ long _count;
+ long _item;
+ ResolvedMethodTableDeleteCheck() : _count(0), _item(0) {}
+ bool operator()(WeakHandle<vm_resolved_method_table_data>* val) {
+ ++_item;
+ oop tmp = val->peek();
+ if (tmp == NULL) {
+ ++_count;
+ return true;
+ } else {
+ return false;
}
}
- log_debug(membername, table) ("ResolvedMethod entries counted %d removed %d",
- _oops_counted, _oops_removed);
- _total_oops_removed += _oops_removed;
- _dead_entries = false;
+};
+
+void ResolvedMethodTable::clean_dead_entries(JavaThread* jt) {
+ ResolvedMethodTableHash::BulkDeleteTask bdt(_local_table);
+ if (!bdt.prepare(jt)) {
+ return;
+ }
+ ResolvedMethodTableDeleteCheck stdc;
+ ResolvedMethodTableDoDelete stdd;
+ {
+ TraceTime timer("Clean", TRACETIME_LOG(Debug, membername, table, perf));
+ while(bdt.do_task(jt, stdc, stdd)) {
+ bdt.pause(jt);
+ {
+ ThreadBlockInVM tbivm(jt);
+ }
+ bdt.cont(jt);
+ }
+ bdt.done(jt);
+ }
+ log_info(membername, table)("Cleaned %ld of %ld", stdc._count, stdc._item);
+}
+void ResolvedMethodTable::reset_dead_counter() {
+ _uncleaned_items_count = 0;
+}
+
+void ResolvedMethodTable::inc_dead_counter(size_t ndead) {
+ size_t total = Atomic::add(ndead, &_uncleaned_items_count);
+ log_trace(membername, table)(
+ "Uncleaned items:" SIZE_FORMAT " added: " SIZE_FORMAT " total:" SIZE_FORMAT,
+ _uncleaned_items_count, ndead, total);
}
-#ifndef PRODUCT
-void ResolvedMethodTable::print() {
- MutexLocker ml(ResolvedMethodTable_lock);
- for (int i = 0; i < table_size(); ++i) {
- ResolvedMethodEntry* entry = bucket(i);
- while (entry != NULL) {
- tty->print("%d : ", i);
- oop rmethod_name = entry->object_no_keepalive();
- if (rmethod_name != NULL) {
- rmethod_name->print();
- Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(rmethod_name);
- m->print();
- }
- entry = entry->next();
+// After the parallel walk this method must be called to trigger
+// cleaning. Note it might trigger a resize instead.
+void ResolvedMethodTable::finish_dead_counter() {
+ check_concurrent_work();
+
+#ifdef ASSERT
+ if (SafepointSynchronize::is_at_safepoint()) {
+ size_t fail_cnt = verify_and_compare_entries();
+ if (fail_cnt != 0) {
+ tty->print_cr("ERROR: fail_cnt=" SIZE_FORMAT, fail_cnt);
+ guarantee(fail_cnt == 0, "unexpected ResolvedMethodTable verification failures");
}
}
+#endif // ASSERT
}
-#endif // PRODUCT
#if INCLUDE_JVMTI
+class AdjustMethodEntries : public StackObj {
+ bool* _trace_name_printed;
+public:
+ AdjustMethodEntries(bool* trace_name_printed) : _trace_name_printed(trace_name_printed) {};
+ bool operator()(WeakHandle<vm_resolved_method_table_data>* entry) {
+ oop mem_name = entry->peek();
+ if (mem_name == NULL) {
+ // Removed
+ return true;
+ }
+
+ Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
+
+ if (old_method->is_old()) {
+
+ Method* new_method = (old_method->is_deleted()) ?
+ Universe::throw_no_such_method_error() :
+ old_method->get_new_method();
+ java_lang_invoke_ResolvedMethodName::set_vmtarget(mem_name, new_method);
+
+ ResourceMark rm;
+ if (!(*_trace_name_printed)) {
+ log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
+ *_trace_name_printed = true;
+ }
+ log_debug(redefine, class, update, constantpool)
+ ("ResolvedMethod method update: %s(%s)",
+ new_method->name()->as_C_string(), new_method->signature()->as_C_string());
+ }
+
+ return true;
+ }
+};
+
// It is called at safepoint only for RedefineClasses
void ResolvedMethodTable::adjust_method_entries(bool * trace_name_printed) {
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
// For each entry in RMT, change to new method
- for (int i = 0; i < _the_table->table_size(); ++i) {
- for (ResolvedMethodEntry* entry = _the_table->bucket(i);
- entry != NULL;
- entry = entry->next()) {
-
- oop mem_name = entry->object_no_keepalive();
- // except ones removed
- if (mem_name == NULL) {
- continue;
- }
- Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
-
- if (old_method->is_old()) {
+ AdjustMethodEntries adjust(trace_name_printed);
+ _local_table->do_safepoint_scan(adjust);
+}
+#endif // INCLUDE_JVMTI
- Method* new_method = (old_method->is_deleted()) ?
- Universe::throw_no_such_method_error() :
- old_method->get_new_method();
- java_lang_invoke_ResolvedMethodName::set_vmtarget(mem_name, new_method);
-
- ResourceMark rm;
- if (!(*trace_name_printed)) {
- log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
- *trace_name_printed = true;
- }
- log_debug(redefine, class, update, constantpool)
- ("ResolvedMethod method update: %s(%s)",
- new_method->name()->as_C_string(), new_method->signature()->as_C_string());
+// Verification and comp
+class VerifyCompResolvedMethod : StackObj {
+ GrowableArray<oop>* _oops;
+ public:
+ size_t _errors;
+ VerifyCompResolvedMethod(GrowableArray<oop>* oops) : _oops(oops), _errors(0) {}
+ bool operator()(WeakHandle<vm_resolved_method_table_data>* val) {
+ oop s = val->peek();
+ if (s == NULL) {
+ return true;
+ }
+ int len = _oops->length();
+ for (int i = 0; i < len; i++) {
+ bool eq = s == _oops->at(i);
+ assert(!eq, "Duplicate entries");
+ if (eq) {
+ _errors++;
}
}
- }
+ _oops->push(s);
+ return true;
+ };
+};
+
+size_t ResolvedMethodTable::items_count() {
+ return _items_count;
}
-#endif // INCLUDE_JVMTI
+
+size_t ResolvedMethodTable::verify_and_compare_entries() {
+ Thread* thr = Thread::current();
+ GrowableArray<oop>* oops =
+ new (ResourceObj::C_HEAP, mtInternal)
+ GrowableArray<oop>((int)_current_size, true);
+
+ VerifyCompResolvedMethod vcs(oops);
+ if (!_local_table->try_scan(thr, vcs)) {
+ log_info(membername, table)("verify unavailable at this moment");
+ }
+ delete oops;
+ return vcs._errors;
+}
--- a/src/hotspot/share/prims/resolvedMethodTable.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/prims/resolvedMethodTable.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -25,89 +25,78 @@
#ifndef SHARE_PRIMS_RESOLVEDMETHODTABLE_HPP
#define SHARE_PRIMS_RESOLVEDMETHODTABLE_HPP
+#include "gc/shared/oopStorage.hpp"
+#include "gc/shared/oopStorageParState.hpp"
+#include "memory/allocation.hpp"
#include "oops/symbol.hpp"
#include "oops/weakHandle.hpp"
+#include "utilities/concurrentHashTable.hpp"
#include "utilities/hashtable.hpp"
-// Hashtable to record Method* used in ResolvedMethods, via. ResolvedMethod oops.
-// This is needed for redefinition to replace Method* with redefined versions.
-
-// Entry in a ResolvedMethodTable, mapping a ClassLoaderWeakHandle for a single oop of
-// java_lang_invoke_ResolvedMethodName which holds JVM Method* in vmtarget.
-
-class ResolvedMethodEntry : public HashtableEntry<ClassLoaderWeakHandle, mtClass> {
- public:
- ResolvedMethodEntry* next() const {
- return (ResolvedMethodEntry*)HashtableEntry<ClassLoaderWeakHandle, mtClass>::next();
- }
-
- ResolvedMethodEntry** next_addr() {
- return (ResolvedMethodEntry**)HashtableEntry<ClassLoaderWeakHandle, mtClass>::next_addr();
- }
-
- oop object();
- oop object_no_keepalive();
-
- void print_on(outputStream* st) const;
-};
+class ResolvedMethodTable;
+class ResolvedMethodTableConfig;
+typedef ConcurrentHashTable<WeakHandle<vm_resolved_method_table_data>, ResolvedMethodTableConfig, mtClass> ResolvedMethodTableHash;
-class ResolvedMethodTable : public Hashtable<ClassLoaderWeakHandle, mtClass> {
- enum Constants {
- _table_size = 1007
- };
-
- static int _total_oops_removed;
-
- static bool _dead_entries;
+class ResolvedMethodTable : public AllStatic {
+ static ResolvedMethodTableHash* _local_table;
+ static size_t _current_size;
- static ResolvedMethodTable* _the_table;
-private:
- ResolvedMethodEntry* bucket(int i) {
- return (ResolvedMethodEntry*) Hashtable<ClassLoaderWeakHandle, mtClass>::bucket(i);
- }
+ static OopStorage* _weak_handles;
- ResolvedMethodEntry** bucket_addr(int i) {
- return (ResolvedMethodEntry**) Hashtable<ClassLoaderWeakHandle, mtClass>::bucket_addr(i);
- }
-
- unsigned int compute_hash(Method* method);
+ static volatile bool _has_work;
- // need not be locked; no state change
- oop lookup(int index, unsigned int hash, Method* method);
- oop lookup(Method* method);
-
- // must be done under ResolvedMethodTable_lock
- oop basic_add(Method* method, Handle rmethod_name);
+ static volatile size_t _items_count;
+ static volatile size_t _uncleaned_items_count;
public:
- ResolvedMethodTable();
+ // Initialization
+ static void create_table();
- static void create_table() {
- assert(_the_table == NULL, "One symbol table allowed.");
- _the_table = new ResolvedMethodTable();
- }
+ static size_t table_size();
+
+ // Lookup and inserts
+ static oop find_method(const Method* method);
+ static oop add_method(const Method* method, Handle rmethod_name);
- // Called from java_lang_invoke_ResolvedMethodName
- static oop find_method(Method* method);
- static oop add_method(const methodHandle& method, Handle rmethod_name);
+ // Callbacks
+ static void item_added();
+ static void item_removed();
+
+ // Cleaning
+ static bool has_work();
- static bool has_work() { return _dead_entries; }
- static void trigger_cleanup();
+ // GC Support - Backing storage for the oop*s
+ static OopStorage* weak_storage();
+
+ // Cleaning and table management
+
+ static double get_load_factor();
+ static double get_dead_factor();
- static int removed_entries_count() { return _total_oops_removed; };
+ static void check_concurrent_work();
+ static void trigger_concurrent_work();
+ static void do_concurrent_work(JavaThread* jt);
-#if INCLUDE_JVMTI
- // It is called at safepoint only for RedefineClasses
- static void adjust_method_entries(bool * trace_name_printed);
-#endif // INCLUDE_JVMTI
+ static void grow(JavaThread* jt);
+ static void clean_dead_entries(JavaThread* jt);
+
+ // GC Notification
- // Cleanup cleared entries
- static void unlink();
+ // Must be called before a parallel walk where objects might die.
+ static void reset_dead_counter();
+ // After the parallel walk this method must be called to trigger
+ // cleaning. Note it might trigger a resize instead.
+ static void finish_dead_counter();
+ // If GC uses ParState directly it should add the number of cleared
+ // entries to this method.
+ static void inc_dead_counter(size_t ndead);
-#ifndef PRODUCT
- void print();
-#endif
- void verify();
+ // JVMTI Support - It is called at safepoint only for RedefineClasses
+ JVMTI_ONLY(static void adjust_method_entries(bool * trace_name_printed);)
+
+ // Debugging
+ static size_t items_count();
+ static size_t verify_and_compare_entries();
};
#endif // SHARE_PRIMS_RESOLVEDMETHODTABLE_HPP
--- a/src/hotspot/share/prims/whitebox.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/prims/whitebox.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -2092,8 +2092,8 @@
#endif
WB_END
-WB_ENTRY(jint, WB_ResolvedMethodRemovedCount(JNIEnv* env, jobject o))
- return (jint) ResolvedMethodTable::removed_entries_count();
+WB_ENTRY(jlong, WB_ResolvedMethodItemsCount(JNIEnv* env, jobject o))
+ return (jlong) ResolvedMethodTable::items_count();
WB_END
WB_ENTRY(jint, WB_ProtectionDomainRemovedCount(JNIEnv* env, jobject o))
@@ -2337,7 +2337,7 @@
{CC"isContainerized", CC"()Z", (void*)&WB_IsContainerized },
{CC"printOsInfo", CC"()V", (void*)&WB_PrintOsInfo },
{CC"disableElfSectionCache", CC"()V", (void*)&WB_DisableElfSectionCache },
- {CC"resolvedMethodRemovedCount", CC"()I", (void*)&WB_ResolvedMethodRemovedCount },
+ {CC"resolvedMethodItemsCount", CC"()J", (void*)&WB_ResolvedMethodItemsCount },
{CC"protectionDomainRemovedCount", CC"()I", (void*)&WB_ProtectionDomainRemovedCount },
{CC"aotLibrariesCount", CC"()I", (void*)&WB_AotLibrariesCount },
};
--- a/src/hotspot/share/runtime/interfaceSupport.inline.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/runtime/interfaceSupport.inline.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -66,22 +66,6 @@
static void verify_stack();
static void verify_last_frame();
# endif
-
- public:
- static void serialize_thread_state_with_handler(JavaThread* thread) {
- serialize_thread_state_internal(thread, true);
- }
-
- // Should only call this if we know that we have a proper SEH set up.
- static void serialize_thread_state(JavaThread* thread) {
- serialize_thread_state_internal(thread, false);
- }
-
- private:
- static void serialize_thread_state_internal(JavaThread* thread, bool needs_exception_handler) {
- // Make sure new state is seen by VM thread
- OrderAccess::fence();
- }
};
@@ -103,28 +87,8 @@
assert(from != _thread_in_native, "use transition_from_native");
assert((from & 1) == 0 && (to & 1) == 0, "odd numbers are transitions states");
assert(thread->thread_state() == from, "coming from wrong thread state");
- // Change to transition state
- thread->set_thread_state((JavaThreadState)(from + 1));
-
- InterfaceSupport::serialize_thread_state(thread);
-
- SafepointMechanism::block_if_requested(thread);
- thread->set_thread_state(to);
-
- CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();)
- }
-
- // transition_and_fence must be used on any thread state transition
- // where there might not be a Java call stub on the stack, in
- // particular on Windows where the Structured Exception Handler is
- // set up in the call stub.
- static inline void transition_and_fence(JavaThread *thread, JavaThreadState from, JavaThreadState to) {
- assert(thread->thread_state() == from, "coming from wrong thread state");
- assert((from & 1) == 0 && (to & 1) == 0, "odd numbers are transitions states");
- // Change to transition state
- thread->set_thread_state((JavaThreadState)(from + 1));
-
- InterfaceSupport::serialize_thread_state_with_handler(thread);
+ // Change to transition state and ensure it is seen by the VM thread.
+ thread->set_thread_state_fence((JavaThreadState)(from + 1));
SafepointMechanism::block_if_requested(thread);
thread->set_thread_state(to);
@@ -143,19 +107,14 @@
static inline void transition_from_native(JavaThread *thread, JavaThreadState to) {
assert((to & 1) == 0, "odd numbers are transitions states");
assert(thread->thread_state() == _thread_in_native, "coming from wrong thread state");
- // Change to transition state
- thread->set_thread_state(_thread_in_native_trans);
-
- InterfaceSupport::serialize_thread_state_with_handler(thread);
+ // Change to transition state and ensure it is seen by the VM thread.
+ thread->set_thread_state_fence(_thread_in_native_trans);
// We never install asynchronous exceptions when coming (back) in
// to the runtime from native code because the runtime is not set
// up to handle exceptions floating around at arbitrary points.
if (SafepointMechanism::should_block(thread) || thread->is_suspend_after_native()) {
JavaThread::check_safepoint_and_suspend_for_native_trans(thread);
-
- // Clear unhandled oops anywhere where we could block, even if we don't.
- CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();)
}
thread->set_thread_state(to);
@@ -164,7 +123,6 @@
void trans(JavaThreadState from, JavaThreadState to) { transition(_thread, from, to); }
void trans_from_java(JavaThreadState to) { transition_from_java(_thread, to); }
void trans_from_native(JavaThreadState to) { transition_from_native(_thread, to); }
- void trans_and_fence(JavaThreadState from, JavaThreadState to) { transition_and_fence(_thread, from, to); }
};
class ThreadInVMForHandshake : public ThreadStateTransition {
@@ -173,9 +131,8 @@
void transition_back() {
// This can be invoked from transition states and must return to the original state properly
assert(_thread->thread_state() == _thread_in_vm, "should only call when leaving VM after handshake");
- _thread->set_thread_state(_thread_in_vm_trans);
-
- InterfaceSupport::serialize_thread_state(_thread);
+ // Change to transition state and ensure it is seen by the VM thread.
+ _thread->set_thread_state_fence(_thread_in_vm_trans);
SafepointMechanism::block_if_requested(_thread);
@@ -217,7 +174,6 @@
class ThreadInVMfromUnknown {
- private:
JavaThread* _thread;
public:
ThreadInVMfromUnknown() : _thread(NULL) {
@@ -236,7 +192,7 @@
}
~ThreadInVMfromUnknown() {
if (_thread) {
- ThreadStateTransition::transition_and_fence(_thread, _thread_in_vm, _thread_in_native);
+ ThreadStateTransition::transition(_thread, _thread_in_vm, _thread_in_native);
}
}
};
@@ -248,7 +204,7 @@
trans_from_native(_thread_in_vm);
}
~ThreadInVMfromNative() {
- trans_and_fence(_thread_in_vm, _thread_in_native);
+ trans(_thread_in_vm, _thread_in_native);
}
};
@@ -260,7 +216,7 @@
// Block, if we are in the middle of a safepoint synchronization.
assert(!thread->owns_locks(), "must release all locks when leaving VM");
thread->frame_anchor()->make_walkable(thread);
- trans_and_fence(_thread_in_vm, _thread_in_native);
+ trans(_thread_in_vm, _thread_in_native);
// Check for pending. async. exceptions or suspends.
if (_thread->has_special_runtime_exit_condition()) _thread->handle_special_runtime_exit_condition(false);
}
@@ -279,10 +235,10 @@
: ThreadStateTransition(thread) {
// Once we are blocked vm expects stack to be walkable
thread->frame_anchor()->make_walkable(thread);
- trans_and_fence(_thread_in_vm, _thread_blocked);
+ trans(_thread_in_vm, _thread_blocked);
}
~ThreadBlockInVM() {
- trans_and_fence(_thread_blocked, _thread_in_vm);
+ trans(_thread_blocked, _thread_in_vm);
OrderAccess::cross_modify_fence();
// We don't need to clear_walkable because it will happen automagically when we return to java
}
@@ -322,14 +278,10 @@
OrderAccess::storestore();
thread->set_thread_state(_thread_blocked);
-
- CHECK_UNHANDLED_OOPS_ONLY(_thread->clear_unhandled_oops();)
}
~ThreadBlockInVMWithDeadlockCheck() {
- // Change to transition state
- _thread->set_thread_state((JavaThreadState)(_thread_blocked_trans));
-
- InterfaceSupport::serialize_thread_state_with_handler(_thread);
+ // Change to transition state and ensure it is seen by the VM thread.
+ _thread->set_thread_state_fence((JavaThreadState)(_thread_blocked_trans));
if (SafepointMechanism::should_block(_thread)) {
release_monitor();
@@ -337,8 +289,6 @@
}
_thread->set_thread_state(_thread_in_vm);
- CHECK_UNHANDLED_OOPS_ONLY(_thread->clear_unhandled_oops();)
-
OrderAccess::cross_modify_fence();
}
};
--- a/src/hotspot/share/runtime/mutex.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/runtime/mutex.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -159,7 +159,7 @@
// !no_safepoint_check logically implies java_thread
guarantee(no_safepoint_check || self->is_Java_thread(), "invariant");
- #ifdef ASSERT
+#ifdef ASSERT
Monitor * least = get_least_ranked_lock_besides_this(self->owned_locks());
assert(least != this, "Specification of get_least_... call above");
if (least != NULL && least->rank() <= special) {
@@ -168,7 +168,14 @@
name(), rank(), least->name(), least->rank());
assert(false, "Shouldn't block(wait) while holding a lock of rank special");
}
- #endif // ASSERT
+#endif // ASSERT
+
+#ifdef CHECK_UNHANDLED_OOPS
+ // Clear unhandled oops in JavaThreads so we get a crash right away.
+ if (self->is_Java_thread() && !no_safepoint_check) {
+ self->clear_unhandled_oops();
+ }
+#endif // CHECK_UNHANDLED_OOPS
int wait_status;
// conceptually set the owner to NULL in anticipation of
--- a/src/hotspot/share/runtime/mutexLocker.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/runtime/mutexLocker.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -54,7 +54,8 @@
Mutex* JNIHandleBlockFreeList_lock = NULL;
Mutex* VMWeakAlloc_lock = NULL;
Mutex* VMWeakActive_lock = NULL;
-Mutex* ResolvedMethodTable_lock = NULL;
+Mutex* ResolvedMethodTableWeakAlloc_lock = NULL;
+Mutex* ResolvedMethodTableWeakActive_lock = NULL;
Mutex* JmethodIdCreation_lock = NULL;
Mutex* JfieldIdCreation_lock = NULL;
Monitor* JNICritical_lock = NULL;
@@ -212,6 +213,9 @@
def(StringTableWeakAlloc_lock , PaddedMutex , vmweak, true, Monitor::_safepoint_check_never);
def(StringTableWeakActive_lock , PaddedMutex , vmweak-1, true, Monitor::_safepoint_check_never);
+ def(ResolvedMethodTableWeakAlloc_lock , PaddedMutex , vmweak, true, Monitor::_safepoint_check_never);
+ def(ResolvedMethodTableWeakActive_lock , PaddedMutex , vmweak-1, true, Monitor::_safepoint_check_never);
+
if (UseConcMarkSweepGC || UseG1GC) {
def(FullGCCount_lock , PaddedMonitor, leaf, true, Monitor::_safepoint_check_never); // in support of ExplicitGCInvokesConcurrent
}
@@ -298,7 +302,6 @@
def(Heap_lock , PaddedMonitor, nonleaf+1, false, Monitor::_safepoint_check_sometimes);
def(JfieldIdCreation_lock , PaddedMutex , nonleaf+1, true, Monitor::_safepoint_check_always); // jfieldID, Used in VM_Operation
- def(ResolvedMethodTable_lock , PaddedMutex , nonleaf+1, false, Monitor::_safepoint_check_always); // Used to protect ResolvedMethodTable
def(CompiledIC_lock , PaddedMutex , nonleaf+2, false, Monitor::_safepoint_check_never); // locks VtableStubs_lock, InlineCacheBuffer_lock
def(CompileTaskAlloc_lock , PaddedMutex , nonleaf+2, true, Monitor::_safepoint_check_always);
--- a/src/hotspot/share/runtime/mutexLocker.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/runtime/mutexLocker.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -48,7 +48,8 @@
extern Mutex* JNIHandleBlockFreeList_lock; // a lock on the JNI handle block free list
extern Mutex* VMWeakAlloc_lock; // VM Weak Handles storage allocate list lock
extern Mutex* VMWeakActive_lock; // VM Weak Handles storage active list lock
-extern Mutex* ResolvedMethodTable_lock; // a lock on the ResolvedMethodTable updates
+extern Mutex* ResolvedMethodTableWeakAlloc_lock; // ResolvedMethodTable weak storage allocate list
+extern Mutex* ResolvedMethodTableWeakActive_lock; // ResolvedMethodTable weak storage active list
extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers
extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers
extern Monitor* JNICritical_lock; // a lock used while entering and exiting JNI critical regions, allows GC to sometimes get in
--- a/src/hotspot/share/runtime/safepoint.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/runtime/safepoint.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -805,9 +805,9 @@
// This part we can skip if we notice we miss or are in a future safepoint.
OrderAccess::storestore();
- thread->set_thread_state(_thread_blocked);
+ // Load in wait barrier should not float up
+ thread->set_thread_state_fence(_thread_blocked);
- OrderAccess::fence(); // Load in wait barrier should not float up
_wait_barrier->wait(static_cast<int>(safepoint_id));
assert(_state != _synchronized, "Can't be");
--- a/src/hotspot/share/runtime/serviceThread.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/runtime/serviceThread.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -190,7 +190,7 @@
}
if (resolved_method_table_work) {
- ResolvedMethodTable::unlink();
+ ResolvedMethodTable::do_concurrent_work(jt);
}
if (protection_domain_table_work) {
--- a/src/hotspot/share/runtime/thread.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/runtime/thread.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -1837,7 +1837,7 @@
// Thread is now sufficiently initialized to be handled by the safepoint code as being
// in the VM. Change thread state from _thread_new to _thread_in_vm
- ThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm);
+ ThreadStateTransition::transition(this, _thread_new, _thread_in_vm);
// Before a thread is on the threads list it is always safe, so after leaving the
// _thread_new we should emit a instruction barrier. The distance to modified code
// from here is probably far enough, but this is consistent and safe.
@@ -2475,11 +2475,10 @@
JavaThreadState state = thread_state();
set_thread_state(_thread_blocked);
java_suspend_self();
- set_thread_state(state);
+ set_thread_state_fence(state);
// Since we are not using a regular thread-state transition helper here,
// we must manually emit the instruction barrier after leaving a safe state.
OrderAccess::cross_modify_fence();
- InterfaceSupport::serialize_thread_state_with_handler(this);
if (state != _thread_in_native) {
SafepointMechanism::block_if_requested(this);
}
--- a/src/hotspot/share/runtime/thread.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/runtime/thread.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -1288,6 +1288,7 @@
// Safepoint support
inline JavaThreadState thread_state() const;
inline void set_thread_state(JavaThreadState s);
+ inline void set_thread_state_fence(JavaThreadState s); // fence after setting thread state
inline ThreadSafepointState* safepoint_state() const;
inline void set_safepoint_state(ThreadSafepointState* state);
inline bool is_at_poll_safepoint();
--- a/src/hotspot/share/runtime/thread.inline.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/runtime/thread.inline.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -141,6 +141,11 @@
#endif
}
+inline void JavaThread::set_thread_state_fence(JavaThreadState s) {
+ set_thread_state(s);
+ OrderAccess::fence();
+}
+
ThreadSafepointState* JavaThread::safepoint_state() const {
return _safepoint_state;
}
--- a/src/hotspot/share/runtime/vm_version.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/runtime/vm_version.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* 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,8 @@
unsigned int Abstract_VM_Version::_logical_processors_per_package = 1U;
unsigned int Abstract_VM_Version::_L1_data_cache_line_size = 0;
+VirtualizationType Abstract_VM_Version::_detected_virtualization = NoDetectedVirtualization;
+
#ifndef HOTSPOT_VERSION_STRING
#error HOTSPOT_VERSION_STRING must be defined
#endif
@@ -295,7 +297,6 @@
(Abstract_VM_Version::vm_build_number() & 0xFF);
}
-
void VM_Version_init() {
VM_Version::initialize();
@@ -306,3 +307,27 @@
os::print_cpu_info(&ls, buf, sizeof(buf));
}
}
+
+bool Abstract_VM_Version::print_matching_lines_from_file(const char* filename, outputStream* st, const char* keywords_to_match[]) {
+ char line[500];
+ FILE* fp = fopen(filename, "r");
+ if (fp == NULL) {
+ return false;
+ }
+
+ st->print_cr("Virtualization information:");
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ int i = 0;
+ while (keywords_to_match[i] != NULL) {
+ if (strncmp(line, keywords_to_match[i], strlen(keywords_to_match[i])) == 0) {
+ st->print("%s", line);
+ break;
+ }
+ i++;
+ }
+ }
+ fclose(fp);
+ return true;
+}
+
+
--- a/src/hotspot/share/runtime/vm_version.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/runtime/vm_version.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -29,6 +29,14 @@
#include "utilities/ostream.hpp"
#include "utilities/macros.hpp"
+typedef enum {
+ NoDetectedVirtualization,
+ XenHVM,
+ KVM,
+ VMWare,
+ HyperV
+} VirtualizationType;
+
// VM_Version provides information about the VM.
class Abstract_VM_Version: AllStatic {
@@ -57,6 +65,8 @@
static int _vm_patch_version;
static int _vm_build_number;
+ static VirtualizationType _detected_virtualization;
+
public:
// Called as part of the runtime services initialization which is
// called from the management module initialization (via init_globals())
@@ -111,6 +121,14 @@
return _features_string;
}
+ static VirtualizationType get_detected_virtualization() {
+ return _detected_virtualization;
+ }
+
+ // platforms that need to specialize this
+ // define VM_Version::print_platform_virtualization_info()
+ static void print_platform_virtualization_info(outputStream*) { }
+
// does HW support an 8-byte compare-exchange operation?
static bool supports_cx8() {
#ifdef SUPPORTS_NATIVE_CX8
@@ -149,6 +167,8 @@
// Does this CPU support spin wait instruction?
static bool supports_on_spin_wait() { return false; }
+
+ static bool print_matching_lines_from_file(const char* filename, outputStream* st, const char* keywords_to_match[]);
};
#include CPU_HEADER(vm_version)
--- a/src/hotspot/share/utilities/exceptions.hpp Tue Apr 09 16:11:54 2019 -0400
+++ b/src/hotspot/share/utilities/exceptions.hpp Thu Apr 11 07:44:51 2019 -0400
@@ -237,11 +237,7 @@
// visible within the scope containing the THROW. Usually this is achieved by declaring the function
// with a TRAPS argument.
-#ifdef THIS_FILE
-#define THREAD_AND_LOCATION THREAD, THIS_FILE, __LINE__
-#else
#define THREAD_AND_LOCATION THREAD, __FILE__, __LINE__
-#endif
#define THROW_OOP(e) \
{ Exceptions::_throw_oop(THREAD_AND_LOCATION, e); return; }
--- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Thu Apr 11 07:44:51 2019 -0400
@@ -92,19 +92,57 @@
}
/**
- * Creates an AbstractStringBuilder with the specified coder and with
- * the initial capacity equal to the smaller of (length + addition)
- * and Integer.MAX_VALUE.
+ * Constructs an AbstractStringBuilder that contains the same characters
+ * as the specified {@code String}. The initial capacity of
+ * the string builder is {@code 16} plus the length of the
+ * {@code String} argument.
+ *
+ * @param str the string to copy.
*/
- AbstractStringBuilder(byte coder, int length, int addition) {
+ AbstractStringBuilder(String str) {
+ int length = str.length();
+ int capacity = (length < Integer.MAX_VALUE - 16)
+ ? length + 16 : Integer.MAX_VALUE;
+ final byte initCoder = str.coder();
+ coder = initCoder;
+ value = (initCoder == LATIN1)
+ ? new byte[capacity] : StringUTF16.newBytesFor(capacity);
+ append(str);
+ }
+
+ /**
+ * Constructs an AbstractStringBuilder that contains the same characters
+ * as the specified {@code CharSequence}. The initial capacity of
+ * the string builder is {@code 16} plus the length of the
+ * {@code CharSequence} argument.
+ *
+ * @param seq the sequence to copy.
+ */
+ AbstractStringBuilder(CharSequence seq) {
+ int length = seq.length();
if (length < 0) {
throw new NegativeArraySizeException("Negative length: " + length);
}
- this.coder = coder;
- int capacity = (length < Integer.MAX_VALUE - addition)
- ? length + addition : Integer.MAX_VALUE;
- value = (coder == LATIN1)
+ int capacity = (length < Integer.MAX_VALUE - 16)
+ ? length + 16 : Integer.MAX_VALUE;
+
+ final byte initCoder;
+ if (COMPACT_STRINGS) {
+ if (seq instanceof AbstractStringBuilder) {
+ initCoder = ((AbstractStringBuilder)seq).getCoder();
+ } else if (seq instanceof String) {
+ initCoder = ((String)seq).coder();
+ } else {
+ initCoder = LATIN1;
+ }
+ } else {
+ initCoder = UTF16;
+ }
+
+ coder = initCoder;
+ value = (initCoder == LATIN1)
? new byte[capacity] : StringUTF16.newBytesFor(capacity);
+ append(seq);
}
/**
--- a/src/java.base/share/classes/java/lang/Math.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/java/lang/Math.java Thu Apr 11 07:44:51 2019 -0400
@@ -1274,7 +1274,12 @@
* @since 1.8
*/
public static int floorMod(int x, int y) {
- return x - floorDiv(x, y) * y;
+ int mod = x % y;
+ // if the signs are different and modulo not zero, adjust result
+ if ((mod ^ y) < 0 && mod != 0) {
+ mod += y;
+ }
+ return mod;
}
/**
@@ -1301,7 +1306,7 @@
*/
public static int floorMod(long x, int y) {
// Result cannot overflow the range of int.
- return (int)(x - floorDiv(x, y) * y);
+ return (int)floorMod(x, (long)y);
}
/**
@@ -1327,7 +1332,12 @@
* @since 1.8
*/
public static long floorMod(long x, long y) {
- return x - floorDiv(x, y) * y;
+ long mod = x % y;
+ // if the signs are different and modulo not zero, adjust result
+ if ((x ^ y) < 0 && mod != 0) {
+ mod += y;
+ }
+ return mod;
}
/**
--- a/src/java.base/share/classes/java/lang/String.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/java/lang/String.java Thu Apr 11 07:44:51 2019 -0400
@@ -164,6 +164,12 @@
/** Cache the hash code for the string */
private int hash; // Default to 0
+ /**
+ * Cache if the hash has been calculated as actually being zero, enabling
+ * us to avoid recalculating this.
+ */
+ private boolean hashIsZero; // Default to false;
+
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
@@ -1508,14 +1514,21 @@
* @return a hash code value for this object.
*/
public int hashCode() {
+ // The hash or hashIsZero fields are subject to a benign data race,
+ // making it crucial to ensure that any observable result of the
+ // calculation in this method stays correct under any possible read of
+ // these fields. Necessary restrictions to allow this to be correct
+ // without explicit memory fences or similar concurrency primitives is
+ // that we can ever only write to one of these two fields for a given
+ // String instance, and that the computation is idempotent and derived
+ // from immutable state
int h = hash;
- if (h == 0 && value.length > 0) {
+ if (h == 0 && !hashIsZero) {
h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
- // Avoid issuing a store if the calculated value is also zero:
- // in addition to a minor performance benefit, this allows storing
- // Strings with zero hash code in read-only memory.
- if (h != 0) {
+ if (h == 0) {
+ hashIsZero = true;
+ } else {
hash = h;
}
}
--- a/src/java.base/share/classes/java/lang/StringBuffer.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/java/lang/StringBuffer.java Thu Apr 11 07:44:51 2019 -0400
@@ -148,8 +148,7 @@
*/
@HotSpotIntrinsicCandidate
public StringBuffer(String str) {
- super(str.coder(), str.length(), 16);
- append(str);
+ super(str);
}
/**
@@ -162,8 +161,7 @@
* @since 1.5
*/
public StringBuffer(CharSequence seq) {
- super(String.LATIN1, seq.length(), 16);
- append(seq);
+ super(seq);
}
/**
--- a/src/java.base/share/classes/java/lang/StringBuilder.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/java/lang/StringBuilder.java Thu Apr 11 07:44:51 2019 -0400
@@ -121,8 +121,7 @@
*/
@HotSpotIntrinsicCandidate
public StringBuilder(String str) {
- super(str.coder(), str.length(), 16);
- append(str);
+ super(str);
}
/**
@@ -134,8 +133,7 @@
* @param seq the sequence to copy.
*/
public StringBuilder(CharSequence seq) {
- super(String.LATIN1, seq.length(), 16);
- append(seq);
+ super(seq);
}
/**
--- a/src/java.base/share/classes/java/security/Signature.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/java/security/Signature.java Thu Apr 11 07:44:51 2019 -0400
@@ -40,6 +40,8 @@
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.BadPaddingException;
import javax.crypto.NoSuchPaddingException;
+import jdk.internal.access.JavaSecuritySignatureAccess;
+import jdk.internal.access.SharedSecrets;
import sun.security.util.Debug;
import sun.security.jca.*;
@@ -118,6 +120,34 @@
public abstract class Signature extends SignatureSpi {
+ static {
+ SharedSecrets.setJavaSecuritySignatureAccess(
+ new JavaSecuritySignatureAccess() {
+ @Override
+ public void initVerify(Signature s, PublicKey publicKey,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException {
+ s.initVerify(publicKey, params);
+ }
+ @Override
+ public void initVerify(Signature s,
+ java.security.cert.Certificate certificate,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException {
+ s.initVerify(certificate, params);
+ }
+ @Override
+ public void initSign(Signature s, PrivateKey privateKey,
+ AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException {
+ s.initSign(privateKey, params, random);
+ }
+ });
+ }
+
private static final Debug debug =
Debug.getInstance("jca", "Signature");
@@ -482,6 +512,53 @@
}
/**
+ * Initialize this object for verification. If this method is called
+ * again with different arguments, it negates the effect
+ * of this call.
+ *
+ * @param publicKey the public key of the identity whose signature is
+ * going to be verified.
+ * @param params the parameters used for verifying this signature.
+ *
+ * @exception InvalidKeyException if the key is invalid.
+ * @exception InvalidAlgorithmParameterException if the params is invalid.
+ */
+ final void initVerify(PublicKey publicKey, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ engineInitVerify(publicKey, params);
+ state = VERIFY;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Signature." + algorithm +
+ " verification algorithm from: " + getProviderName());
+ }
+ }
+
+ private static PublicKey getPublicKeyFromCert(Certificate cert)
+ throws InvalidKeyException {
+ // If the certificate is of type X509Certificate,
+ // we should check whether it has a Key Usage
+ // extension marked as critical.
+ //if (cert instanceof java.security.cert.X509Certificate) {
+ if (cert instanceof X509Certificate) {
+ // Check whether the cert has a key usage extension
+ // marked as a critical extension.
+ // The OID for KeyUsage extension is 2.5.29.15.
+ X509Certificate c = (X509Certificate)cert;
+ Set<String> critSet = c.getCriticalExtensionOIDs();
+
+ if (critSet != null && !critSet.isEmpty()
+ && critSet.contains("2.5.29.15")) {
+ boolean[] keyUsageInfo = c.getKeyUsage();
+ // keyUsageInfo[0] is for digitalSignature.
+ if ((keyUsageInfo != null) && (keyUsageInfo[0] == false))
+ throw new InvalidKeyException("Wrong key usage");
+ }
+ }
+ return cert.getPublicKey();
+ }
+
+ /**
* Initializes this object for verification, using the public key from
* the given certificate.
* <p>If the certificate is of type X.509 and has a <i>key usage</i>
@@ -501,27 +578,40 @@
*/
public final void initVerify(Certificate certificate)
throws InvalidKeyException {
- // If the certificate is of type X509Certificate,
- // we should check whether it has a Key Usage
- // extension marked as critical.
- if (certificate instanceof java.security.cert.X509Certificate) {
- // Check whether the cert has a key usage extension
- // marked as a critical extension.
- // The OID for KeyUsage extension is 2.5.29.15.
- X509Certificate cert = (X509Certificate)certificate;
- Set<String> critSet = cert.getCriticalExtensionOIDs();
+ engineInitVerify(getPublicKeyFromCert(certificate));
+ state = VERIFY;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Signature." + algorithm +
+ " verification algorithm from: " + getProviderName());
+ }
+ }
- if (critSet != null && !critSet.isEmpty()
- && critSet.contains("2.5.29.15")) {
- boolean[] keyUsageInfo = cert.getKeyUsage();
- // keyUsageInfo[0] is for digitalSignature.
- if ((keyUsageInfo != null) && (keyUsageInfo[0] == false))
- throw new InvalidKeyException("Wrong key usage");
- }
- }
-
- PublicKey publicKey = certificate.getPublicKey();
- engineInitVerify(publicKey);
+ /**
+ * Initializes this object for verification, using the public key from
+ * the given certificate.
+ * <p>If the certificate is of type X.509 and has a <i>key usage</i>
+ * extension field marked as critical, and the value of the <i>key usage</i>
+ * extension field implies that the public key in
+ * the certificate and its corresponding private key are not
+ * supposed to be used for digital signatures, an
+ * {@code InvalidKeyException} is thrown.
+ *
+ * @param certificate the certificate of the identity whose signature is
+ * going to be verified.
+ * @param params the parameters used for verifying this signature.
+ *
+ * @exception InvalidKeyException if the public key in the certificate
+ * is not encoded properly or does not include required parameter
+ * information or cannot be used for digital signature purposes.
+ * @exception InvalidAlgorithmParameterException if the params is invalid.
+ *
+ * @since 13
+ */
+ final void initVerify(Certificate certificate,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ engineInitVerify(getPublicKeyFromCert(certificate), params);
state = VERIFY;
if (!skipDebug && pdebug != null) {
@@ -575,6 +665,31 @@
}
/**
+ * Initialize this object for signing. If this method is called
+ * again with different arguments, it negates the effect
+ * of this call.
+ *
+ * @param privateKey the private key of the identity whose signature
+ * is going to be generated.
+ * @param params the parameters used for generating signature.
+ * @param random the source of randomness for this signature.
+ *
+ * @exception InvalidKeyException if the key is invalid.
+ * @exception InvalidAlgorithmParameterException if the params is invalid
+ */
+ final void initSign(PrivateKey privateKey,
+ AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ engineInitSign(privateKey, params, random);
+ state = SIGN;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Signature." + algorithm +
+ " signing algorithm from: " + getProviderName());
+ }
+ }
+
+ /**
* Returns the signature bytes of all the data updated.
* The format of the signature depends on the underlying
* signature scheme.
@@ -1110,11 +1225,13 @@
}
}
- private void chooseProvider(int type, Key key, SecureRandom random)
- throws InvalidKeyException {
+ // Used by engineSetParameter/engineInitSign/engineInitVerify() to
+ // find the right provider with the supplied key, parameters, random source
+ private void chooseProvider(int type, Key key,
+ AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
synchronized (lock) {
if (sigSpi != null) {
- init(sigSpi, type, key, random);
return;
}
Exception lastException = null;
@@ -1127,7 +1244,7 @@
s = serviceIterator.next();
}
// if provider says it does not support this key, ignore it
- if (s.supportsParameter(key) == false) {
+ if (key != null && s.supportsParameter(key) == false) {
continue;
}
// if instance is not a SignatureSpi, ignore it
@@ -1136,7 +1253,7 @@
}
try {
SignatureSpi spi = newInstance(s);
- init(spi, type, key, random);
+ tryOperation(spi, type, key, params, random);
provider = s.getProvider();
sigSpi = spi;
firstService = null;
@@ -1158,6 +1275,10 @@
if (lastException instanceof RuntimeException) {
throw (RuntimeException)lastException;
}
+ if (lastException instanceof InvalidAlgorithmParameterException) {
+ throw (InvalidAlgorithmParameterException)lastException;
+ }
+
String k = (key != null) ? key.getClass().getName() : "(null)";
throw new InvalidKeyException
("No installed provider supports this key: "
@@ -1165,22 +1286,35 @@
}
}
- private static final int I_PUB = 1;
- private static final int I_PRIV = 2;
- private static final int I_PRIV_SR = 3;
+ private static final int I_PUB = 1;
+ private static final int I_PRIV = 2;
+ private static final int I_PRIV_SR = 3;
+ private static final int I_PUB_PARAM = 4;
+ private static final int I_PRIV_PARAM_SR = 5;
+ private static final int S_PARAM = 6;
- private void init(SignatureSpi spi, int type, Key key,
- SecureRandom random) throws InvalidKeyException {
+ private void tryOperation(SignatureSpi spi, int type, Key key,
+ AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
switch (type) {
case I_PUB:
spi.engineInitVerify((PublicKey)key);
break;
+ case I_PUB_PARAM:
+ spi.engineInitVerify((PublicKey)key, params);
+ break;
case I_PRIV:
spi.engineInitSign((PrivateKey)key);
break;
case I_PRIV_SR:
spi.engineInitSign((PrivateKey)key, random);
break;
+ case I_PRIV_PARAM_SR:
+ spi.engineInitSign((PrivateKey)key, params, random);
+ break;
+ case S_PARAM:
+ spi.engineSetParameter(params);
+ break;
default:
throw new AssertionError("Internal error: " + type);
}
@@ -1191,7 +1325,22 @@
if (sigSpi != null) {
sigSpi.engineInitVerify(publicKey);
} else {
- chooseProvider(I_PUB, publicKey, null);
+ try {
+ chooseProvider(I_PUB, publicKey, null, null);
+ } catch (InvalidAlgorithmParameterException iape) {
+ // should not happen, re-throw as IKE just in case
+ throw new InvalidKeyException(iape);
+ }
+ }
+ }
+
+ void engineInitVerify(PublicKey publicKey,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (sigSpi != null) {
+ sigSpi.engineInitVerify(publicKey, params);
+ } else {
+ chooseProvider(I_PUB_PARAM, publicKey, params, null);
}
}
@@ -1200,7 +1349,12 @@
if (sigSpi != null) {
sigSpi.engineInitSign(privateKey);
} else {
- chooseProvider(I_PRIV, privateKey, null);
+ try {
+ chooseProvider(I_PRIV, privateKey, null, null);
+ } catch (InvalidAlgorithmParameterException iape) {
+ // should not happen, re-throw as IKE just in case
+ throw new InvalidKeyException(iape);
+ }
}
}
@@ -1209,7 +1363,22 @@
if (sigSpi != null) {
sigSpi.engineInitSign(privateKey, sr);
} else {
- chooseProvider(I_PRIV_SR, privateKey, sr);
+ try {
+ chooseProvider(I_PRIV_SR, privateKey, null, sr);
+ } catch (InvalidAlgorithmParameterException iape) {
+ // should not happen, re-throw as IKE just in case
+ throw new InvalidKeyException(iape);
+ }
+ }
+ }
+
+ void engineInitSign(PrivateKey privateKey,
+ AlgorithmParameterSpec params, SecureRandom sr)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (sigSpi != null) {
+ sigSpi.engineInitSign(privateKey, params, sr);
+ } else {
+ chooseProvider(I_PRIV_PARAM_SR, privateKey, params, sr);
}
}
@@ -1260,8 +1429,16 @@
protected void engineSetParameter(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
- chooseFirstProvider();
- sigSpi.engineSetParameter(params);
+ if (sigSpi != null) {
+ sigSpi.engineSetParameter(params);
+ } else {
+ try {
+ chooseProvider(S_PARAM, null, params, null);
+ } catch (InvalidKeyException ike) {
+ // should never happen, rethrow just in case
+ throw new InvalidAlgorithmParameterException(ike);
+ }
+ }
}
protected Object engineGetParameter(String param)
--- a/src/java.base/share/classes/java/security/SignatureSpi.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/java/security/SignatureSpi.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -72,6 +72,33 @@
/**
* Initializes this signature object with the specified
+ * public key for verification operations.
+ *
+ * @param publicKey the public key of the identity whose signature is
+ * going to be verified.
+ * @param params the parameters for generating this signature
+ *
+ * @exception InvalidKeyException if the key is improperly
+ * encoded, does not work with the given parameters, and so on.
+ * @exception InvalidAlgorithmParameterException if the given parameters
+ * is invalid.
+ */
+ void engineInitVerify(PublicKey publicKey,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (params != null) {
+ try {
+ engineSetParameter(params);
+ } catch (UnsupportedOperationException usoe) {
+ // error out if not overrridden
+ throw new InvalidAlgorithmParameterException(usoe);
+ }
+ }
+ engineInitVerify(publicKey);
+ }
+
+ /**
+ * Initializes this signature object with the specified
* private key for signing operations.
*
* @param privateKey the private key of the identity whose signature
@@ -98,10 +125,41 @@
* encoded, parameters are missing, and so on.
*/
protected void engineInitSign(PrivateKey privateKey,
- SecureRandom random)
- throws InvalidKeyException {
- this.appRandom = random;
- engineInitSign(privateKey);
+ SecureRandom random)
+ throws InvalidKeyException {
+ this.appRandom = random;
+ engineInitSign(privateKey);
+ }
+
+ /**
+ * Initializes this signature object with the specified
+ * private key and source of randomness for signing operations.
+ *
+ * <p>This concrete method has been added to this previously-defined
+ * abstract class. (For backwards compatibility, it cannot be abstract.)
+ *
+ * @param privateKey the private key of the identity whose signature
+ * will be generated.
+ * @param params the parameters for generating this signature
+ * @param random the source of randomness
+ *
+ * @exception InvalidKeyException if the key is improperly
+ * encoded, parameters are missing, and so on.
+ * @exception InvalidAlgorithmParameterException if the parameters is
+ * invalid.
+ */
+ void engineInitSign(PrivateKey privateKey,
+ AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (params != null) {
+ try {
+ engineSetParameter(params);
+ } catch (UnsupportedOperationException usoe) {
+ // error out if not overrridden
+ throw new InvalidAlgorithmParameterException(usoe);
+ }
+ }
+ engineInitSign(privateKey, random);
}
/**
@@ -127,7 +185,7 @@
* properly
*/
protected abstract void engineUpdate(byte[] b, int off, int len)
- throws SignatureException;
+ throws SignatureException;
/**
* Updates the data to be signed or verified using the specified
@@ -223,7 +281,7 @@
* @since 1.2
*/
protected int engineSign(byte[] outbuf, int offset, int len)
- throws SignatureException {
+ throws SignatureException {
byte[] sig = engineSign();
if (len < sig.length) {
throw new SignatureException
@@ -251,7 +309,7 @@
* process the input data provided, etc.
*/
protected abstract boolean engineVerify(byte[] sigBytes)
- throws SignatureException;
+ throws SignatureException;
/**
* Verifies the passed-in signature in the specified array
@@ -273,7 +331,7 @@
* @since 1.4
*/
protected boolean engineVerify(byte[] sigBytes, int offset, int length)
- throws SignatureException {
+ throws SignatureException {
byte[] sigBytesCopy = new byte[length];
System.arraycopy(sigBytes, offset, sigBytesCopy, 0, length);
return engineVerify(sigBytesCopy);
@@ -305,7 +363,7 @@
*/
@Deprecated
protected abstract void engineSetParameter(String param, Object value)
- throws InvalidParameterException;
+ throws InvalidParameterException;
/**
* <p>This method is overridden by providers to initialize
@@ -321,8 +379,8 @@
* are inappropriate for this signature engine
*/
protected void engineSetParameter(AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException {
- throw new UnsupportedOperationException();
+ throws InvalidAlgorithmParameterException {
+ throw new UnsupportedOperationException();
}
/**
--- a/src/java.base/share/classes/java/security/cert/X509CRL.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/java/security/cert/X509CRL.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -239,16 +239,15 @@
public void verify(PublicKey key, Provider sigProvider)
throws CRLException, NoSuchAlgorithmException,
InvalidKeyException, SignatureException {
+ String sigAlgName = getSigAlgName();
Signature sig = (sigProvider == null)
- ? Signature.getInstance(getSigAlgName())
- : Signature.getInstance(getSigAlgName(), sigProvider);
+ ? Signature.getInstance(sigAlgName)
+ : Signature.getInstance(sigAlgName, sigProvider);
- sig.initVerify(key);
-
- // set parameters after Signature.initSign/initVerify call,
- // so the deferred provider selections occur when key is set
try {
- SignatureUtil.specialSetParameter(sig, getSigAlgParams());
+ byte[] paramBytes = getSigAlgParams();
+ SignatureUtil.initVerifyWithParam(sig, key,
+ SignatureUtil.getParamSpec(sigAlgName, paramBytes));
} catch (ProviderException e) {
throw new CRLException(e.getMessage(), e.getCause());
} catch (InvalidAlgorithmParameterException e) {
--- a/src/java.base/share/classes/java/security/cert/X509Certificate.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/java/security/cert/X509Certificate.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -676,16 +676,14 @@
public void verify(PublicKey key, Provider sigProvider)
throws CertificateException, NoSuchAlgorithmException,
InvalidKeyException, SignatureException {
+ String sigName = getSigAlgName();
Signature sig = (sigProvider == null)
- ? Signature.getInstance(getSigAlgName())
- : Signature.getInstance(getSigAlgName(), sigProvider);
+ ? Signature.getInstance(sigName)
+ : Signature.getInstance(sigName, sigProvider);
- sig.initVerify(key);
-
- // set parameters after Signature.initSign/initVerify call,
- // so the deferred provider selections occur when key is set
try {
- SignatureUtil.specialSetParameter(sig, getSigAlgParams());
+ SignatureUtil.initVerifyWithParam(sig, key,
+ SignatureUtil.getParamSpec(sigName, getSigAlgParams()));
} catch (ProviderException e) {
throw new CertificateException(e.getMessage(), e.getCause());
} catch (InvalidAlgorithmParameterException e) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/access/JavaSecuritySignatureAccess.java Thu Apr 11 07:44:51 2019 -0400
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+package jdk.internal.access;
+
+import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
+
+public interface JavaSecuritySignatureAccess {
+
+ void initVerify(Signature s, PublicKey publicKey, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ void initVerify(Signature s, java.security.cert.Certificate certificate,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ void initSign(Signature s, PrivateKey privateKey,
+ AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+}
--- a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java Thu Apr 11 07:44:51 2019 -0400
@@ -36,6 +36,7 @@
import java.io.ObjectInputStream;
import java.io.RandomAccessFile;
import java.security.ProtectionDomain;
+import java.security.Signature;
import jdk.internal.misc.Unsafe;
/** A repository of "shared secrets", which are a mechanism for
@@ -73,6 +74,7 @@
private static JavaObjectInputStreamAccess javaObjectInputStreamAccess;
private static JavaObjectInputFilterAccess javaObjectInputFilterAccess;
private static JavaIORandomAccessFileAccess javaIORandomAccessFileAccess;
+ private static JavaSecuritySignatureAccess javaSecuritySignatureAccess;
private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess;
public static JavaUtilJarAccess javaUtilJarAccess() {
@@ -327,6 +329,17 @@
return javaIORandomAccessFileAccess;
}
+ public static void setJavaSecuritySignatureAccess(JavaSecuritySignatureAccess jssa) {
+ javaSecuritySignatureAccess = jssa;
+ }
+
+ public static JavaSecuritySignatureAccess getJavaSecuritySignatureAccess() {
+ if (javaSecuritySignatureAccess == null) {
+ unsafe.ensureClassInitialized(Signature.class);
+ }
+ return javaSecuritySignatureAccess;
+ }
+
public static void setJavaxCryptoSealedObjectAccess(JavaxCryptoSealedObjectAccess jcsoa) {
javaxCryptoSealedObjectAccess = jcsoa;
}
--- a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -447,15 +447,13 @@
Signature sig = Signature.getInstance(algname);
- sig.initVerify(key);
-
- // set parameters after Signature.initSign/initVerify call,
- // so the deferred provider selections occur when key is set
AlgorithmParameters ap =
digestEncryptionAlgorithmId.getParameters();
try {
- SignatureUtil.specialSetParameter(sig, ap);
- } catch (ProviderException | InvalidAlgorithmParameterException e) {
+ SignatureUtil.initVerifyWithParam(sig, key,
+ SignatureUtil.getParamSpec(algname, ap));
+ } catch (ProviderException | InvalidAlgorithmParameterException |
+ InvalidKeyException e) {
throw new SignatureException(e.getMessage(), e);
}
@@ -466,8 +464,6 @@
} catch (IOException e) {
throw new SignatureException("IO error verifying signature:\n" +
e.getMessage());
- } catch (InvalidKeyException e) {
- throw new SignatureException("InvalidKey: " + e.getMessage());
}
return null;
}
--- a/src/java.base/share/classes/sun/security/pkcs10/PKCS10.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/sun/security/pkcs10/PKCS10.java Thu Apr 11 07:44:51 2019 -0400
@@ -167,12 +167,8 @@
try {
sigAlg = id.getName();
sig = Signature.getInstance(sigAlg);
-
- sig.initVerify(subjectPublicKeyInfo);
-
- // set parameters after Signature.initSign/initVerify call,
- // so the deferred provider selections occur when key is set
- SignatureUtil.specialSetParameter(sig, id.getParameters());
+ SignatureUtil.initVerifyWithParam(sig, subjectPublicKeyInfo,
+ SignatureUtil.getParamSpec(sigAlg, id.getParameters()));
sig.update(data);
if (!sig.verify(sigData)) {
--- a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java Thu Apr 11 07:44:51 2019 -0400
@@ -43,6 +43,7 @@
import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
import sun.security.ssl.X509Authentication.X509Possession;
import sun.security.util.KeyUtil;
+import sun.security.util.SignatureUtil;
enum SignatureScheme {
// EdDSA algorithms
@@ -471,16 +472,11 @@
Signature signer = Signature.getInstance(algorithm);
if (key instanceof PublicKey) {
- signer.initVerify((PublicKey)(key));
+ SignatureUtil.initVerifyWithParam(signer, (PublicKey)key,
+ signAlgParameter);
} else {
- signer.initSign((PrivateKey)key);
- }
-
- // Important note: Please don't set the parameters before signature
- // or verification initialization, so that the crypto provider can
- // be selected properly.
- if (signAlgParameter != null) {
- signer.setParameter(signAlgParameter);
+ SignatureUtil.initSignWithParam(signer, (PrivateKey)key,
+ signAlgParameter, null);
}
return signer;
--- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java Thu Apr 11 07:44:51 2019 -0400
@@ -84,6 +84,7 @@
import sun.security.util.Password;
import sun.security.util.SecurityProperties;
import sun.security.util.SecurityProviderConstants;
+import sun.security.util.SignatureUtil;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
@@ -1441,11 +1442,12 @@
sigAlgName = getCompatibleSigAlgName(privateKey);
}
Signature signature = Signature.getInstance(sigAlgName);
- signature.initSign(privateKey);
+ AlgorithmParameterSpec params = AlgorithmId
+ .getDefaultAlgorithmParameterSpec(sigAlgName, privateKey);
+
+ SignatureUtil.initSignWithParam(signature, privateKey, params, null);
X509CertInfo info = new X509CertInfo();
- AlgorithmParameterSpec params = AlgorithmId
- .getDefaultAlgorithmParameterSpec(sigAlgName, privateKey);
AlgorithmId algID = AlgorithmId.getWithParameterSpec(sigAlgName, params);
info.set(X509CertInfo.VALIDITY, interval);
info.set(X509CertInfo.SERIAL_NUMBER,
@@ -1599,12 +1601,9 @@
}
Signature signature = Signature.getInstance(sigAlgName);
- signature.initSign(privKey);
AlgorithmParameterSpec params = AlgorithmId
.getDefaultAlgorithmParameterSpec(sigAlgName, privKey);
- if (params != null) {
- signature.setParameter(params);
- }
+ SignatureUtil.initSignWithParam(signature, privKey, params, null);
X500Name subject = dname == null?
new X500Name(((X509Certificate)cert).getSubjectDN().toString()):
--- a/src/java.base/share/classes/sun/security/util/SignatureUtil.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/sun/security/util/SignatureUtil.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* 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.security.*;
import java.security.spec.*;
import sun.security.rsa.RSAUtil;
+import jdk.internal.access.SharedSecrets;
/**
* Utility class for Signature related operations. Currently used by various
@@ -39,12 +40,25 @@
*/
public class SignatureUtil {
+ private static String checkName(String algName) throws ProviderException {
+ if (algName.indexOf(".") == -1) {
+ return algName;
+ }
+ // convert oid to String
+ try {
+ return Signature.getInstance(algName).getAlgorithm();
+ } catch (Exception e) {
+ throw new ProviderException("Error mapping algorithm name", e);
+ }
+ }
+
// Utility method of creating an AlgorithmParameters object with
// the specified algorithm name and encoding
private static AlgorithmParameters createAlgorithmParameters(String algName,
byte[] paramBytes) throws ProviderException {
try {
+ algName = checkName(algName);
AlgorithmParameters result =
AlgorithmParameters.getInstance(algName);
result.init(paramBytes);
@@ -54,52 +68,81 @@
}
}
- private static AlgorithmParameterSpec getParamSpec(String sigName,
+ // Utility method for converting the specified AlgorithmParameters object
+ // into an AlgorithmParameterSpec object.
+ public static AlgorithmParameterSpec getParamSpec(String sigName,
AlgorithmParameters params)
- throws InvalidAlgorithmParameterException, ProviderException {
+ throws ProviderException {
- if (params == null) return null;
-
- if (sigName.toUpperCase().indexOf("RSA") == -1) {
- throw new ProviderException
- ("Unrecognized algorithm for signature parameters " +
- sigName);
+ sigName = checkName(sigName);
+ AlgorithmParameterSpec paramSpec = null;
+ if (params != null) {
+ if (sigName.toUpperCase().indexOf("RSA") == -1) {
+ throw new ProviderException
+ ("Unrecognized algorithm for signature parameters " +
+ sigName);
+ }
+ // AlgorithmParameters.getAlgorithm() may returns oid if it's
+ // created during DER decoding. Convert to use the standard name
+ // before passing it to RSAUtil
+ if (params.getAlgorithm().indexOf(".") != -1) {
+ try {
+ params = createAlgorithmParameters(sigName,
+ params.getEncoded());
+ } catch (IOException e) {
+ throw new ProviderException(e);
+ }
+ }
+ paramSpec = RSAUtil.getParamSpec(params);
}
- // AlgorithmParameters.getAlgorithm() may returns oid if it's
- // created during DER decoding. Convert to use the standard name
- // before passing it to RSAUtil
- String alg = params.getAlgorithm();
- if (alg.equalsIgnoreCase(sigName) || alg.indexOf(".") != -1) {
- try {
- params = createAlgorithmParameters(sigName,
- params.getEncoded());
- } catch (IOException e) {
- throw new ProviderException(e);
- }
- }
- return RSAUtil.getParamSpec(params);
+ return paramSpec;
}
- // Special method for setting the specified parameter bytes into the
- // specified Signature object as signature parameters.
- public static void specialSetParameter(Signature sig, byte[] paramBytes)
- throws InvalidAlgorithmParameterException, ProviderException {
+ // Utility method for converting the specified parameter bytes into an
+ // AlgorithmParameterSpec object.
+ public static AlgorithmParameterSpec getParamSpec(String sigName,
+ byte[] paramBytes)
+ throws ProviderException {
+ sigName = checkName(sigName);
+ AlgorithmParameterSpec paramSpec = null;
if (paramBytes != null) {
- String sigName = sig.getAlgorithm();
+ if (sigName.toUpperCase().indexOf("RSA") == -1) {
+ throw new ProviderException
+ ("Unrecognized algorithm for signature parameters " +
+ sigName);
+ }
AlgorithmParameters params =
createAlgorithmParameters(sigName, paramBytes);
- specialSetParameter(sig, params);
+ paramSpec = RSAUtil.getParamSpec(params);
}
+ return paramSpec;
}
- // Special method for setting the specified AlgorithmParameter object
- // into the specified Signature object as signature parameters.
- public static void specialSetParameter(Signature sig,
- AlgorithmParameters params)
- throws InvalidAlgorithmParameterException, ProviderException {
- if (params != null) {
- String sigName = sig.getAlgorithm();
- sig.setParameter(getParamSpec(sigName, params));
- }
+ // Utility method for initializing the specified Signature object
+ // for verification with the specified key and params (may be null)
+ public static void initVerifyWithParam(Signature s, PublicKey key,
+ AlgorithmParameterSpec params)
+ throws ProviderException, InvalidAlgorithmParameterException,
+ InvalidKeyException {
+ SharedSecrets.getJavaSecuritySignatureAccess().initVerify(s, key, params);
+ }
+
+ // Utility method for initializing the specified Signature object
+ // for verification with the specified Certificate and params (may be null)
+ public static void initVerifyWithParam(Signature s,
+ java.security.cert.Certificate cert,
+ AlgorithmParameterSpec params)
+ throws ProviderException, InvalidAlgorithmParameterException,
+ InvalidKeyException {
+ SharedSecrets.getJavaSecuritySignatureAccess().initVerify(s, cert, params);
+ }
+
+ // Utility method for initializing the specified Signature object
+ // for signing with the specified key and params (may be null)
+ public static void initSignWithParam(Signature s, PrivateKey key,
+ AlgorithmParameterSpec params, SecureRandom sr)
+ throws ProviderException, InvalidAlgorithmParameterException,
+ InvalidKeyException {
+ SharedSecrets.getJavaSecuritySignatureAccess().initSign(s, key, params, sr);
}
}
--- a/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -370,18 +370,16 @@
throw new CRLException("Uninitialized CRL");
}
Signature sigVerf = null;
+ String sigName = sigAlgId.getName();
if (sigProvider.isEmpty()) {
- sigVerf = Signature.getInstance(sigAlgId.getName());
+ sigVerf = Signature.getInstance(sigName);
} else {
- sigVerf = Signature.getInstance(sigAlgId.getName(), sigProvider);
+ sigVerf = Signature.getInstance(sigName, sigProvider);
}
- sigVerf.initVerify(key);
-
- // set parameters after Signature.initSign/initVerify call,
- // so the deferred provider selection happens when key is set
try {
- SignatureUtil.specialSetParameter(sigVerf, getSigAlgParams());
+ SignatureUtil.initVerifyWithParam(sigVerf, key,
+ SignatureUtil.getParamSpec(sigName, getSigAlgParams()));
} catch (ProviderException e) {
throw new CRLException(e.getMessage(), e.getCause());
} catch (InvalidAlgorithmParameterException e) {
@@ -425,18 +423,16 @@
throw new CRLException("Uninitialized CRL");
}
Signature sigVerf = null;
+ String sigName = sigAlgId.getName();
if (sigProvider == null) {
- sigVerf = Signature.getInstance(sigAlgId.getName());
+ sigVerf = Signature.getInstance(sigName);
} else {
- sigVerf = Signature.getInstance(sigAlgId.getName(), sigProvider);
+ sigVerf = Signature.getInstance(sigName, sigProvider);
}
- sigVerf.initVerify(key);
-
- // set parameters after Signature.initSign/initVerify call,
- // so the deferred provider selection happens when key is set
try {
- SignatureUtil.specialSetParameter(sigVerf, getSigAlgParams());
+ SignatureUtil.initVerifyWithParam(sigVerf, key,
+ SignatureUtil.getParamSpec(sigName, getSigAlgParams()));
} catch (ProviderException e) {
throw new CRLException(e.getMessage(), e.getCause());
} catch (InvalidAlgorithmParameterException e) {
@@ -502,7 +498,7 @@
sigEngine.initSign(key);
- // in case the name is reset
+ // in case the name is reset
sigAlgId = AlgorithmId.get(sigEngine.getAlgorithm());
infoSigAlgId = sigAlgId;
--- a/src/java.base/share/classes/sun/security/x509/X509CertImpl.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.base/share/classes/sun/security/x509/X509CertImpl.java Thu Apr 11 07:44:51 2019 -0400
@@ -422,18 +422,16 @@
}
// Verify the signature ...
Signature sigVerf = null;
+ String sigName = algId.getName();
if (sigProvider.isEmpty()) {
- sigVerf = Signature.getInstance(algId.getName());
+ sigVerf = Signature.getInstance(sigName);
} else {
- sigVerf = Signature.getInstance(algId.getName(), sigProvider);
+ sigVerf = Signature.getInstance(sigName, sigProvider);
}
- sigVerf.initVerify(key);
-
- // set parameters after Signature.initSign/initVerify call,
- // so the deferred provider selection happens when key is set
try {
- SignatureUtil.specialSetParameter(sigVerf, getSigAlgParams());
+ SignatureUtil.initVerifyWithParam(sigVerf, key,
+ SignatureUtil.getParamSpec(sigName, getSigAlgParams()));
} catch (ProviderException e) {
throw new CertificateException(e.getMessage(), e.getCause());
} catch (InvalidAlgorithmParameterException e) {
@@ -478,18 +476,16 @@
}
// Verify the signature ...
Signature sigVerf = null;
+ String sigName = algId.getName();
if (sigProvider == null) {
- sigVerf = Signature.getInstance(algId.getName());
+ sigVerf = Signature.getInstance(sigName);
} else {
- sigVerf = Signature.getInstance(algId.getName(), sigProvider);
+ sigVerf = Signature.getInstance(sigName, sigProvider);
}
- sigVerf.initVerify(key);
-
- // set parameters after Signature.initSign/initVerify call,
- // so the deferred provider selection happens when key is set
try {
- SignatureUtil.specialSetParameter(sigVerf, getSigAlgParams());
+ SignatureUtil.initVerifyWithParam(sigVerf, key,
+ SignatureUtil.getParamSpec(sigName, getSigAlgParams()));
} catch (ProviderException e) {
throw new CertificateException(e.getMessage(), e.getCause());
} catch (InvalidAlgorithmParameterException e) {
@@ -587,22 +583,19 @@
InvalidKeyException, InvalidAlgorithmParameterException,
NoSuchProviderException, SignatureException {
try {
- if (readOnly)
+ if (readOnly) {
throw new CertificateEncodingException(
- "cannot over-write existing certificate");
+ "cannot over-write existing certificate");
+ }
Signature sigEngine = null;
- if (provider == null || provider.isEmpty())
+ if (provider == null || provider.isEmpty()) {
sigEngine = Signature.getInstance(algorithm);
- else
+ } else {
sigEngine = Signature.getInstance(algorithm, provider);
-
- sigEngine.initSign(key);
+ }
- if (signingParams != null) {
- // set parameters after Signature.initSign/initVerify call, so
- // the deferred provider selection happens when the key is set
- sigEngine.setParameter(signingParams);
- }
+ SignatureUtil.initSignWithParam(sigEngine, key, signingParams,
+ null);
// in case the name is reset
if (signingParams != null) {
--- a/src/java.desktop/share/classes/com/sun/media/sound/FastSysexMessage.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.desktop/share/classes/com/sun/media/sound/FastSysexMessage.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
* 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,9 +37,7 @@
FastSysexMessage(byte[] data) throws InvalidMidiDataException {
super(data);
- if (data.length==0 || (((data[0] & 0xFF) != 0xF0) && ((data[0] & 0xFF) != 0xF7))) {
- super.setMessage(data, data.length); // will throw Exception
- }
+ MidiUtils.checkSysexStatus(data, data.length);
}
/**
@@ -54,9 +52,7 @@
// which is shared among all transmitters, cannot be modified
@Override
public void setMessage(byte[] data, int length) throws InvalidMidiDataException {
- if ((data.length == 0) || (((data[0] & 0xFF) != 0xF0) && ((data[0] & 0xFF) != 0xF7))) {
- super.setMessage(data, data.length); // will throw Exception
- }
+ MidiUtils.checkSysexStatus(data, length);
this.length = length;
this.data = new byte[this.length];
System.arraycopy(data, 0, this.data, 0, length);
--- a/src/java.desktop/share/classes/com/sun/media/sound/MidiUtils.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.desktop/share/classes/com/sun/media/sound/MidiUtils.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* 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,7 @@
import java.util.ArrayList;
+import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiEvent;
@@ -34,6 +35,9 @@
import javax.sound.midi.Sequence;
import javax.sound.midi.Track;
+import static javax.sound.midi.SysexMessage.SPECIAL_SYSTEM_EXCLUSIVE;
+import static javax.sound.midi.SysexMessage.SYSTEM_EXCLUSIVE;
+
// TODO:
// - define and use a global symbolic constant for 60000000 (see convertTempo)
@@ -65,6 +69,37 @@
"MidiDevice %s not supported by this provider", info));
}
+ /**
+ * Checks the status byte for the system exclusive message.
+ *
+ * @param data the system exclusive message data
+ * @param length the length of the valid message data in the array
+ * @throws InvalidMidiDataException if the status byte is invalid for a
+ * system exclusive message
+ */
+ public static void checkSysexStatus(final byte[] data, final int length)
+ throws InvalidMidiDataException {
+ if (data.length == 0 || length == 0) {
+ throw new InvalidMidiDataException("Status byte is missing");
+ }
+ checkSysexStatus(data[0] & 0xFF);
+ }
+
+ /**
+ * Checks the status byte for the system exclusive message.
+ *
+ * @param status the status byte for the message (0xF0 or 0xF7)
+ * @throws InvalidMidiDataException if the status byte is invalid for a
+ * system exclusive message
+ */
+ public static void checkSysexStatus(final int status)
+ throws InvalidMidiDataException {
+ if (status != SYSTEM_EXCLUSIVE && status != SPECIAL_SYSTEM_EXCLUSIVE) {
+ throw new InvalidMidiDataException(String.format(
+ "Invalid status byte for sysex message: 0x%X", status));
+ }
+ }
+
/** return true if the passed message is Meta End Of Track */
public static boolean isMetaEndOfTrack(MidiMessage midiMsg) {
// first check if it is a META message at all
--- a/src/java.desktop/share/classes/javax/sound/midi/SysexMessage.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.desktop/share/classes/javax/sound/midi/SysexMessage.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* 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,6 +25,8 @@
package javax.sound.midi;
+import com.sun.media.sound.MidiUtils;
+
/**
* A {@code SysexMessage} object represents a MIDI system exclusive message.
* <p>
@@ -183,10 +185,7 @@
*/
@Override
public void setMessage(byte[] data, int length) throws InvalidMidiDataException {
- int status = (data[0] & 0xFF);
- if ((status != 0xF0) && (status != 0xF7)) {
- throw new InvalidMidiDataException("Invalid status byte for sysex message: 0x" + Integer.toHexString(status));
- }
+ MidiUtils.checkSysexStatus(data, length);
super.setMessage(data, length);
}
@@ -200,9 +199,7 @@
* system exclusive message
*/
public void setMessage(int status, byte[] data, int length) throws InvalidMidiDataException {
- if ( (status != 0xF0) && (status != 0xF7) ) {
- throw new InvalidMidiDataException("Invalid status byte for sysex message: 0x" + Integer.toHexString(status));
- }
+ MidiUtils.checkSysexStatus(status);
if (length < 0 || length > data.length) {
throw new IndexOutOfBoundsException("length out of bounds: "+length);
}
--- a/src/java.desktop/share/classes/javax/swing/text/ElementIterator.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.desktop/share/classes/javax/swing/text/ElementIterator.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* 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,65 +25,58 @@
package javax.swing.text;
+import java.util.Enumeration;
import java.util.Stack;
-import java.util.Enumeration;
/**
+ * {@code ElementIterator}, as the name suggests, iterates over the
+ * {@code Element} tree. The constructor can be invoked with either
+ * {@code Document} or an {@code Element} as an argument. If the constructor is
+ * invoked with a {@code Document} as an argument then the root of the iteration
+ * is the return value of {@code document.getDefaultRootElement()}.
* <p>
- * ElementIterator, as the name suggests, iterates over the Element
- * tree. The constructor can be invoked with either Document or an Element
- * as an argument. If the constructor is invoked with a Document as an
- * argument then the root of the iteration is the return value of
- * document.getDefaultRootElement().
- *
- * The iteration happens in a depth-first manner. In terms of how
- * boundary conditions are handled:
- * a) if next() is called before first() or current(), the
- * root will be returned.
- * b) next() returns null to indicate the end of the list.
- * c) previous() returns null when the current element is the root
- * or next() has returned null.
- *
- * The ElementIterator does no locking of the Element tree. This means
- * that it does not track any changes. It is the responsibility of the
+ * The iteration happens in a depth-first manner. In terms of how boundary
+ * conditions are handled:
+ * <ul>
+ * <li>if {@link #next} is called before {@link #first} or {@link #current},
+ * the root will be returned
+ * <li>{@link #next} returns {@code null} to indicate the end of the list
+ * <li>{@link #previous} returns {@code null} when the current element is the
+ * root or {@link #next} has returned {@code null}
+ * </ul>
+ * <p>
+ * The {@code ElementIterator} does no locking of the {@code Element} tree. This
+ * means that it does not track any changes. It is the responsibility of the
* user of this class, to ensure that no changes happen during element
* iteration.
- *
+ * <p>
* Simple usage example:
- *
- * public void iterate() {
- * ElementIterator it = new ElementIterator(root);
- * Element elem;
- * while (true) {
- * if ((elem = next()) != null) {
- * // process element
- * System.out.println("elem: " + elem.getName());
- * } else {
- * break;
- * }
- * }
- * }
+ * <pre>{@code public void iterate() {
+ * ElementIterator it = new ElementIterator(root);
+ * Element elem;
+ * while (true) {
+ * if ((elem = it.next()) != null) {
+ * // process element
+ * System.out.println("elem: " + elem.getName());
+ * } else {
+ * break;
+ * }
+ * }
+ * }}</pre>
*
* @author Sunita Mani
- *
*/
-
public class ElementIterator implements Cloneable {
-
private Element root;
private Stack<StackItem> elementStack = null;
/**
- * The StackItem class stores the element
- * as well as a child index. If the
- * index is -1, then the element represented
- * on the stack is the element itself.
- * Otherwise, the index functions as an index
- * into the vector of children of the element.
- * In this case, the item on the stack
- * represents the "index"th child of the element
- *
+ * The {@code StackItem} class stores the element as well as a child index.
+ * If the index is -1, then the element represented on the stack is the
+ * element itself. Otherwise, the index functions as an index into the
+ * vector of children of the element. In this case, the item on the stack
+ * represents the "index"th child of the element.
*/
private class StackItem implements Cloneable {
Element item;
@@ -117,31 +110,28 @@
}
/**
- * Creates a new ElementIterator. The
- * root element is taken to get the
- * default root element of the document.
+ * Creates a new {@code ElementIterator}. The root element is taken to get
+ * the default root element of the document.
*
- * @param document a Document.
+ * @param document a {@code Document}
*/
public ElementIterator(Document document) {
root = document.getDefaultRootElement();
}
-
/**
- * Creates a new ElementIterator.
+ * Creates a new {@code ElementIterator}.
*
- * @param root the root Element.
+ * @param root the root {@code Element}
*/
public ElementIterator(Element root) {
this.root = root;
}
-
/**
- * Clones the ElementIterator.
+ * Clones the {@code ElementIterator}.
*
- * @return a cloned ElementIterator Object.
+ * @return a cloned {@code ElementIterator} Object
*/
public synchronized Object clone() {
@@ -161,11 +151,10 @@
}
}
-
/**
* Fetches the first element.
*
- * @return an Element.
+ * @return an {@code Element}
*/
public Element first() {
// just in case...
@@ -183,7 +172,7 @@
/**
* Fetches the current depth of element tree.
*
- * @return the depth.
+ * @return the depth
*/
public int depth() {
if (elementStack == null) {
@@ -192,12 +181,11 @@
return elementStack.size();
}
-
/**
- * Fetches the current Element.
+ * Fetches the current {@code Element}.
*
- * @return element on top of the stack or
- * <code>null</code> if the root element is <code>null</code>
+ * @return element on top of the stack or {@code null} if the root element
+ * is {@code null}
*/
public Element current() {
@@ -222,14 +210,11 @@
return null;
}
-
/**
- * Fetches the next Element. The strategy
- * used to locate the next element is
- * a depth-first search.
+ * Fetches the next {@code Element}. The strategy used to locate the next
+ * element is a depth-first search.
*
- * @return the next element or <code>null</code>
- * at the end of the list.
+ * @return the next element or {@code null} at the end of the list
*/
public Element next() {
@@ -282,14 +267,12 @@
return null;
}
-
/**
- * Fetches the previous Element. If however the current
- * element is the last element, or the current element
- * is null, then null is returned.
+ * Fetches the previous {@code Element}. If however the current element is
+ * the last element, or the current element is {@code null}, then
+ * {@code null} is returned.
*
- * @return previous <code>Element</code> if available
- *
+ * @return previous {@code Element} if available
*/
public Element previous() {
@@ -335,8 +318,8 @@
}
/**
- * Returns the last child of <code>parent</code> that is a leaf. If the
- * last child is a not a leaf, this method is called with the last child.
+ * Returns the last child of {@code parent} that is a leaf. If the last
+ * child is a not a leaf, this method is called with the last child.
*/
private Element getDeepestLeaf(Element parent) {
if (parent.isLeaf()) {
@@ -349,10 +332,10 @@
return getDeepestLeaf(parent.getElement(childCount - 1));
}
- /*
- Iterates through the element tree and prints
- out each element and its attributes.
- */
+ /**
+ * Iterates through the element tree and prints out each element and its
+ * attributes.
+ */
private void dumpTree() {
Element elem;
--- a/src/java.desktop/share/classes/javax/swing/text/View.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.desktop/share/classes/javax/swing/text/View.java Thu Apr 11 07:44:51 2019 -0400
@@ -229,7 +229,6 @@
* Typically the view is told to render into the span
* that is returned, although there is no guarantee.
* The parent may choose to resize or break the view
- * @see View#getPreferredSpan
*/
public abstract float getPreferredSpan(int axis);
--- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c Tue Apr 09 16:11:54 2019 -0400
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c Thu Apr 11 07:44:51 2019 -0400
@@ -1777,9 +1777,18 @@
(widget_type == CHECK_BOX || widget_type == RADIO_BUTTON)) {
return;
}
- GtkStyleContext* context = get_style(widget_type, detail);
+
+ GtkStyleContext* context = NULL;
if (widget_type == TOOL_TIP) {
+ context = get_style(widget_type, detail);
fp_gtk_style_context_add_class(context, "background");
+ } else {
+ gtk3_widget = gtk3_get_widget(widget_type);
+ context = fp_gtk_widget_get_style_context (gtk3_widget);
+ fp_gtk_style_context_save (context);
+ if (detail != 0) {
+ transform_detail_string(detail, context);
+ }
}
GtkStateFlags flags = get_gtk_flags(state_type);
@@ -1795,8 +1804,11 @@
}
fp_gtk_render_background (context, cr, x, y, width, height);
-
- disposeOrRestoreContext(context);
+ if (widget_type == TOOL_TIP) {
+ disposeOrRestoreContext(context);
+ } else {
+ fp_gtk_style_context_restore (context);
+ }
}
static void gtk3_paint_focus(WidgetType widget_type, GtkStateType state_type,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java Tue Apr 09 16:11:54 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* 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 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -366,9 +367,11 @@
for (Type t : minContext.inferencevars) {
//add listener that forwards notifications to original context
minContext.addFreeTypeListener(List.of(t), (inferenceContext) -> {
- ((UndetVar)asUndetVar(t)).setInst(inferenceContext.asInstType(t));
- infer.doIncorporation(inferenceContext, warn);
- solve(List.from(rv.minMap.get(t)), warn);
+ Type instType = inferenceContext.asInstType(t);
+ for (Type eq : rv.minMap.get(t)) {
+ ((UndetVar)asUndetVar(eq)).setInst(instType);
+ }
+ infer.doIncorporation(this, warn);
notifyChange();
});
}
@@ -385,9 +388,9 @@
class ReachabilityVisitor extends Types.UnaryVisitor<Void> {
- Set<Type> equiv = new HashSet<>();
- Set<Type> min = new HashSet<>();
- Map<Type, Set<Type>> minMap = new HashMap<>();
+ Set<Type> equiv = new LinkedHashSet<>();
+ Set<Type> min = new LinkedHashSet<>();
+ Map<Type, Set<Type>> minMap = new LinkedHashMap<>();
void scan(List<Type> roots) {
roots.stream().forEach(this::visit);
@@ -401,7 +404,7 @@
@Override
public Void visitUndetVar(UndetVar t, Void _unused) {
if (min.add(t.qtype)) {
- Set<Type> deps = minMap.getOrDefault(t.qtype, new HashSet<>(Collections.singleton(t.qtype)));
+ Set<Type> deps = minMap.getOrDefault(t.qtype, new LinkedHashSet<>(Collections.singleton(t.qtype)));
for (InferenceBound boundKind : InferenceBound.values()) {
for (Type b : t.getBounds(boundKind)) {
Type undet = asUndetVar(b);
--- a/test/hotspot/jtreg/ProblemList-graal.txt Tue Apr 09 16:11:54 2019 -0400
+++ b/test/hotspot/jtreg/ProblemList-graal.txt Thu Apr 11 07:44:51 2019 -0400
@@ -218,6 +218,8 @@
vmTestbase/nsk/jdb/clear/clear003/clear003.java 8218701 generic-all
+compiler/jsr292/InvokerSignatureMismatch.java 8221577 generic-all
+
# Graal unit tests
org.graalvm.compiler.core.test.CheckGraalInvariants 8205081
org.graalvm.compiler.core.test.OptionsVerifierTest 8205081
@@ -228,4 +230,3 @@
org.graalvm.compiler.core.test.deopt.CompiledMethodTest 8202955
org.graalvm.compiler.hotspot.test.ReservedStackAccessTest 8213567 windows-all
-
--- a/test/hotspot/jtreg/runtime/MemberName/MemberNameLeak.java Tue Apr 09 16:11:54 2019 -0400
+++ b/test/hotspot/jtreg/runtime/MemberName/MemberNameLeak.java Thu Apr 11 07:44:51 2019 -0400
@@ -25,14 +25,16 @@
* @test
* @bug 8174749 8213307
* @summary MemberNameTable should reuse entries
- * @requires vm.gc == "null"
- * @library /test/lib
+ * @library /test/lib /runtime/testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @modules java.compiler
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. MemberNameLeak
*/
import java.lang.invoke.*;
+import java.lang.reflect.*;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import sun.hotspot.WhiteBox;
@@ -40,6 +42,12 @@
import sun.hotspot.gc.GC;
public class MemberNameLeak {
+ private static String className = "MemberNameLeakTestClass";
+ private static String methodPrefix = "method";
+ // The size of the ResolvedMethodTable is 1024. 2000 entries
+ // is enough to trigger a grow/cleaning of the table after a GC.
+ private static int methodCount = 2000;
+
static class Leak {
public void callMe() {
}
@@ -47,15 +55,31 @@
public static void main(String[] args) throws Throwable {
Leak leak = new Leak();
WhiteBox wb = WhiteBox.getWhiteBox();
- int removedCountOrig = wb.resolvedMethodRemovedCount();
- int removedCount;
+
+ ClassWithManyMethodsClassLoader classLoader = new ClassWithManyMethodsClassLoader();
+ Class<?> clazz = classLoader.create(className, methodPrefix, methodCount);
+
+ long before = wb.resolvedMethodItemsCount();
+
+ Object o = clazz.newInstance();
+ MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
- for (int i = 0; i < 10; i++) {
- MethodHandles.Lookup lookup = MethodHandles.lookup();
- MethodType mt = MethodType.fromMethodDescriptorString("()V", Leak.class.getClassLoader());
+ for (int i = 0; i < methodCount; i++) {
+ MethodType mt = MethodType.fromMethodDescriptorString("()V", classLoader);
+ String methodName = methodPrefix + i;
// findSpecial leaks some native mem
- MethodHandle mh = lookup.findSpecial(Leak.class, "callMe", mt, Leak.class);
- mh.invokeExact(leak);
+ // Add entry to ResolvedMethodTable.
+ MethodHandle mh0 = lookup.findSpecial(clazz, methodName, mt, clazz);
+ // Find entry in ResolvedMethodTable.
+ MethodHandle mh1 = lookup.findSpecial(clazz, methodName, mt, clazz);
+
+ mh1.invoke(o);
+ }
+
+ long after = wb.resolvedMethodItemsCount();
+
+ if (after == before) {
+ throw new RuntimeException("Too few resolved methods");
}
// Wait until ServiceThread cleans ResolvedMethod table
@@ -64,16 +88,19 @@
if (cnt++ % 30 == 0) {
System.gc(); // make mh unused
}
- removedCount = wb.resolvedMethodRemovedCount();
- if (removedCountOrig != removedCount) {
+
+ if (after != wb.resolvedMethodItemsCount()) {
+ // Entries have been removed.
break;
}
+
Thread.sleep(100);
}
}
}
- public static void test(String gc, boolean doConcurrent) throws Throwable {
+ public static void test(GC gc, boolean doConcurrent) throws Throwable {
+ System.err.println("test(" + gc + ", " + doConcurrent + ")");
// Run this Leak class with logging
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-Xlog:membername+table=trace",
@@ -84,27 +111,35 @@
doConcurrent ? "-XX:+ExplicitGCInvokesConcurrent" : "-XX:-ExplicitGCInvokesConcurrent",
"-XX:+ClassUnloading",
"-XX:+ClassUnloadingWithConcurrentMark",
- gc, Leak.class.getName());
+ "-XX:+Use" + gc + "GC",
+ Leak.class.getName());
OutputAnalyzer output = new OutputAnalyzer(pb.start());
- output.shouldContain("ResolvedMethod entry added for MemberNameLeak$Leak.callMe()V");
- output.shouldContain("ResolvedMethod entry found for MemberNameLeak$Leak.callMe()V");
+ // Hardcoded names for classes generated by GeneratedClassLoader
+ String descriptor = className + "." + methodPrefix + "0()V";
+ output.shouldContain("ResolvedMethod entry added for " + descriptor);
+ output.shouldContain("ResolvedMethod entry found for " + descriptor);
output.shouldContain("ResolvedMethod entry removed");
output.shouldHaveExitValue(0);
}
- public static void main(java.lang.String[] unused) throws Throwable {
- test("-XX:+UseG1GC", false);
- test("-XX:+UseG1GC", true);
+ private static boolean supportsSTW(GC gc) {
+ return !(gc == GC.Epsilon);
+ }
- test("-XX:+UseParallelGC", false);
- test("-XX:+UseSerialGC", false);
- if (!Compiler.isGraalEnabled()) { // Graal does not support CMS
- test("-XX:+UseConcMarkSweepGC", false);
- test("-XX:+UseConcMarkSweepGC", true);
- if (GC.Shenandoah.isSupported()) {
- test("-XX:+UseShenandoahGC", true);
- test("-XX:+UseShenandoahGC", false);
- }
+ private static boolean supportsConcurrent(GC gc) {
+ return !(gc == GC.Epsilon || gc == GC.Serial || gc == GC.Parallel);
+ }
+
+ private static void test(GC gc) throws Throwable {
+ if (supportsSTW(gc)) {
+ test(gc, false);
+ }
+ if (supportsConcurrent(gc)) {
+ test(gc, true);
}
}
+
+ public static void main(java.lang.String[] unused) throws Throwable {
+ test(GC.selected());
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/testlibrary/ClassWithManyMethodsClassLoader.java Thu Apr 11 07:44:51 2019 -0400
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * 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.io.DataInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import javax.tools.JavaCompiler;
+import javax.tools.ToolProvider;
+
+/**
+ * A factory that generates a class with many methods.
+ */
+public class ClassWithManyMethodsClassLoader extends ClassLoader {
+ /**
+ * Used to enable/disable keeping the class files and java sources for
+ * the generated classes.
+ */
+ private static boolean deleteFiles = Boolean.parseBoolean(
+ System.getProperty("ClassWithManyMethodsClassLoader.deleteFiles", "true"));
+
+ private JavaCompiler javac;
+
+ public ClassWithManyMethodsClassLoader() {
+ javac = ToolProvider.getSystemJavaCompiler();
+ }
+
+ private String generateSource(String className, String methodPrefix, int methodCount) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("public class ")
+ .append(className)
+ .append("{\n");
+
+ for (int i = 0; i < methodCount; i++) {
+ sb.append("public void ")
+ .append(methodPrefix)
+ .append(i)
+ .append("() {}\n");
+ }
+
+ sb.append("\n}");
+
+ return sb.toString();
+ }
+
+ private byte[] generateClassBytes(String className, String methodPrefix, int methodCount) throws IOException {
+ String src = generateSource(className, methodPrefix, methodCount);
+ File file = new File(className + ".java");
+ try (PrintWriter pw = new PrintWriter(new FileWriter(file))) {
+ pw.append(src);
+ pw.flush();
+ }
+ ByteArrayOutputStream err = new ByteArrayOutputStream();
+ int exitcode = javac.run(null, null, err, file.getCanonicalPath());
+ if (exitcode != 0) {
+ // Print Error
+ System.err.print(err);
+ if (err.toString().contains("java.lang.OutOfMemoryError: Java heap space")) {
+ throw new OutOfMemoryError("javac failed with resources exhausted");
+ } else {
+ throw new RuntimeException("javac failure when compiling: " +
+ file.getCanonicalPath());
+ }
+ } else {
+ if (deleteFiles) {
+ file.delete();
+ }
+ }
+
+ File classFile = new File(className + ".class");
+ byte[] bytes;
+ try (DataInputStream dis = new DataInputStream(new FileInputStream(classFile))) {
+ bytes = new byte[dis.available()];
+ dis.readFully(bytes);
+ }
+ if (deleteFiles) {
+ classFile.delete();
+ }
+
+ return bytes;
+ }
+
+ public Class<?> create(String className, String methodPrefix, int methodCount) throws IOException {
+ byte[] bytes = generateClassBytes(className, methodPrefix, methodCount);
+ return defineClass(className, bytes, 0, bytes.length);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/MyPackage/GenerateEventsTest.java Thu Apr 11 07:44:51 2019 -0400
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * 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 8222072
+ * @summary Send CompiledMethodLoad events only to the environment requested it with GenerateEvents
+ * @compile GenerateEventsTest.java
+ * @run main/othervm/native -agentlib:GenerateEvents1 -agentlib:GenerateEvents2 MyPackage.GenerateEventsTest
+ */
+
+package MyPackage;
+
+public class GenerateEventsTest {
+ static native void agent1GenerateEvents();
+ static native void agent2SetThread(Thread thread);
+ static native boolean agent1FailStatus();
+ static native boolean agent2FailStatus();
+
+ public static void main(String[] args) {
+ agent2SetThread(Thread.currentThread());
+ agent1GenerateEvents(); // Re-generate CompiledMethodLoad events
+ if (agent1FailStatus()|| agent2FailStatus()) {
+ throw new RuntimeException("GenerateEventsTest failed!");
+ }
+ System.out.println("GenerateEventsTest passed!");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents1.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * 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 <string.h>
+#include "jvmti.h"
+
+extern "C" {
+
+#define AGENT_NAME "agent1"
+
+static JavaVM *java_vm = NULL;
+static jthread exp_thread = NULL;
+static jvmtiEnv *jvmti1 = NULL;
+static jint agent1_event_count = 0;
+static bool fail_status = false;
+
+static void
+check_jvmti_status(JNIEnv* env, jvmtiError err, const char* msg) {
+ if (err != JVMTI_ERROR_NONE) {
+ printf("check_jvmti_status: JVMTI function returned error: %d\n", err);
+ fail_status = true;
+ env->FatalError(msg);
+ }
+}
+
+static void JNICALL
+CompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method,
+ jint code_size, const void* code_addr,
+ jint map_length, const jvmtiAddrLocationMap* map,
+ const void* compile_info) {
+ JNIEnv* env = NULL;
+ jthread thread = NULL;
+ char* name = NULL;
+ char* sign = NULL;
+ jvmtiError err;
+
+ // Posted on JavaThread's, so it is legal to obtain JNIEnv*
+ if (java_vm->GetEnv((void **) (&env), JNI_VERSION_9) != JNI_OK) {
+ printf("CompiledMethodLoad: failed to obtain JNIEnv*\n");
+ fail_status = true;
+ return;
+ }
+
+ jvmti->GetCurrentThread(&thread);
+ if (!env->IsSameObject(thread, exp_thread)) {
+ return; // skip events from unexpected threads
+ }
+ agent1_event_count++;
+
+ err = jvmti->GetMethodName(method, &name, &sign, NULL);
+ check_jvmti_status(env, err, "CompiledMethodLoad: Error in JVMTI GetMethodName");
+
+ printf("%s: CompiledMethodLoad: %s%s\n", AGENT_NAME, name, sign);
+ fflush(0);
+}
+
+JNIEXPORT jint JNICALL
+Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
+ jvmtiEventCallbacks callbacks;
+ jvmtiCapabilities caps;
+ jvmtiError err;
+
+ java_vm = jvm;
+ if (jvm->GetEnv((void **) (&jvmti1), JVMTI_VERSION) != JNI_OK) {
+ printf("Agent_OnLoad: Error in GetEnv in obtaining jvmtiEnv*\n");
+ fail_status = true;
+ return JNI_ERR;
+ }
+
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.CompiledMethodLoad = &CompiledMethodLoad;
+
+ err = jvmti1->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks));
+ if (err != JVMTI_ERROR_NONE) {
+ printf("Agent_OnLoad: Error in JVMTI SetEventCallbacks: %d\n", err);
+ fail_status = true;
+ return JNI_ERR;
+ }
+
+ memset(&caps, 0, sizeof(caps));
+ caps.can_generate_compiled_method_load_events = 1;
+
+ err = jvmti1->AddCapabilities(&caps);
+ if (err != JVMTI_ERROR_NONE) {
+ printf("Agent_OnLoad: Error in JVMTI AddCapabilities: %d\n", err);
+ fail_status = true;
+ return JNI_ERR;
+ }
+ return JNI_OK;
+}
+
+JNIEXPORT void JNICALL
+Java_MyPackage_GenerateEventsTest_agent1GenerateEvents(JNIEnv *env, jclass cls) {
+ jthread thread = NULL;
+ jvmtiError err;
+
+ err = jvmti1->GetCurrentThread(&thread);
+ check_jvmti_status(env, err, "generateEvents1: Error in JVMTI GetCurrentThread");
+
+ exp_thread = (jthread)env->NewGlobalRef(thread);
+
+ err = jvmti1->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
+ check_jvmti_status(env, err, "generateEvents1: Error in JVMTI SetEventNotificationMode: JVMTI_ENABLE");
+
+ err = jvmti1->GenerateEvents(JVMTI_EVENT_COMPILED_METHOD_LOAD);
+ check_jvmti_status(env, err, "generateEvents1: Error in JVMTI GenerateEvents");
+
+ err = jvmti1->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
+ check_jvmti_status(env, err, "generateEvents1: Error in JVMTI SetEventNotificationMode: JVMTI_DISABLE");
+}
+
+JNIEXPORT jboolean JNICALL
+Java_MyPackage_GenerateEventsTest_agent1FailStatus(JNIEnv *env, jclass cls) {
+ return fail_status;
+}
+
+} // extern "C"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents2.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * 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 <string.h>
+#include "jvmti.h"
+
+extern "C" {
+
+#define AGENT_NAME "agent2"
+
+static JavaVM *java_vm = NULL;
+static jthread exp_thread = NULL;
+static jvmtiEnv *jvmti2 = NULL;
+static jint agent2_event_count = 0;
+static bool fail_status = false;
+
+static void
+check_jvmti_status(JNIEnv* env, jvmtiError err, const char* msg) {
+ if (err != JVMTI_ERROR_NONE) {
+ printf("check_jvmti_status: JVMTI function returned error: %d\n", err);
+ fail_status = true;
+ env->FatalError(msg);
+ }
+}
+
+static void JNICALL
+CompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method,
+ jint code_size, const void* code_addr,
+ jint map_length, const jvmtiAddrLocationMap* map,
+ const void* compile_info) {
+ JNIEnv* env = NULL;
+ jthread thread = NULL;
+ char* name = NULL;
+ char* sign = NULL;
+ jvmtiError err;
+
+ // Posted on JavaThread's, so it is legal to obtain JNIEnv*
+ if (java_vm->GetEnv((void **) (&env), JNI_VERSION_9) != JNI_OK) {
+ fail_status = true;
+ return;
+ }
+
+ err = jvmti->GetCurrentThread(&thread);
+ check_jvmti_status(env, err, "CompiledMethodLoad: Error in JVMTI GetCurrentThread");
+ if (!env->IsSameObject(thread, exp_thread)) {
+ return; // skip events from unexpected threads
+ }
+ agent2_event_count++;
+
+ err = jvmti->GetMethodName(method, &name, &sign, NULL);
+ check_jvmti_status(env, err, "CompiledMethodLoad: Error in JVMTI GetMethodName");
+
+ printf("%s: CompiledMethodLoad: %s%s\n", AGENT_NAME, name, sign);
+ fflush(0);
+}
+
+JNIEXPORT jint JNICALL
+Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
+ jvmtiEventCallbacks callbacks;
+ jvmtiCapabilities caps;
+ jvmtiError err;
+
+ java_vm = jvm;
+ if (jvm->GetEnv((void **) (&jvmti2), JVMTI_VERSION_9) != JNI_OK) {
+ return JNI_ERR;
+ }
+
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.CompiledMethodLoad = &CompiledMethodLoad;
+
+ err = jvmti2->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks));
+ if (err != JVMTI_ERROR_NONE) {
+ printf("Agent_OnLoad: Error in JVMTI SetEventCallbacks: %d\n", err);
+ fail_status = true;
+ return JNI_ERR;
+ }
+
+ memset(&caps, 0, sizeof(caps));
+ caps.can_generate_compiled_method_load_events = 1;
+
+ err = jvmti2->AddCapabilities(&caps);
+ if (err != JVMTI_ERROR_NONE) {
+ printf("Agent_OnLoad: Error in JVMTI AddCapabilities: %d\n", err);
+ fail_status = true;
+ return JNI_ERR;
+ }
+ return JNI_OK;
+}
+
+JNIEXPORT void JNICALL
+Java_MyPackage_GenerateEventsTest_agent2SetThread(JNIEnv *env, jclass cls, jthread thread) {
+ jvmtiError err;
+
+ exp_thread = (jthread)env->NewGlobalRef(thread);
+
+ err = jvmti2->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
+ check_jvmti_status(env, err, "setThread2: Error in JVMTI SetEventNotificationMode: JVMTI_ENABLE");
+}
+
+JNIEXPORT jboolean JNICALL
+Java_MyPackage_GenerateEventsTest_agent2FailStatus(JNIEnv *env, jclass cls) {
+ jvmtiError err;
+
+ err = jvmti2->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
+ check_jvmti_status(env, err, "check2: Error in JVMTI SetEventNotificationMode: JVMTI_DISABLE");
+
+ printf("\n");
+ if (agent2_event_count == 0) {
+ printf("check2: Zero events in agent2 as expected\n");
+ } else {
+ fail_status = true;
+ printf("check2: Unexpected non-zero event count in agent2: %d\n", agent2_event_count);
+ }
+ printf("\n");
+ fflush(0);
+
+ return fail_status;
+}
+
+} // extern "C"
--- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SingleStep/singlestep001/singlestep001.cpp Tue Apr 09 16:11:54 2019 -0400
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SingleStep/singlestep001/singlestep001.cpp Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* 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 @@
static jvmtiEnv *jvmti = NULL;
static jvmtiEventCallbacks callbacks;
-static int vm_started = 0;
+static volatile int callbacksEnabled = NSK_FALSE;
static jrawMonitorID agent_lock;
static void setBP(jvmtiEnv *jvmti_env, JNIEnv *env, jclass klass) {
@@ -77,7 +77,7 @@
jvmti->RawMonitorEnter(agent_lock);
- if (vm_started) {
+ if (callbacksEnabled) {
if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &sig, &generic)))
env->FatalError("failed to obtain a class signature\n");
@@ -99,6 +99,13 @@
jclass klass;
char *sig, *generic;
+ jvmti->RawMonitorEnter(agent_lock);
+
+ if (!callbacksEnabled) {
+ jvmti->RawMonitorExit(agent_lock);
+ return;
+ }
+
NSK_DISPLAY0("Breakpoint event received\n");
if (!NSK_JVMTI_VERIFY(jvmti_env->GetMethodDeclaringClass(method, &klass)))
NSK_COMPLAIN0("TEST FAILURE: unable to get method declaring class\n\n");
@@ -118,6 +125,7 @@
NSK_COMPLAIN1("TEST FAILURE: unexpected breakpoint event in method of class \"%s\"\n\n",
sig);
}
+ jvmti->RawMonitorExit(agent_lock);
}
void JNICALL
@@ -197,7 +205,16 @@
VMStart(jvmtiEnv *jvmti_env, JNIEnv* jni_env) {
jvmti->RawMonitorEnter(agent_lock);
- vm_started = 1;
+ callbacksEnabled = NSK_TRUE;
+
+ jvmti->RawMonitorExit(agent_lock);
+}
+
+void JNICALL
+VMDeath(jvmtiEnv *jvmti_env, JNIEnv* jni_env) {
+ jvmti->RawMonitorEnter(agent_lock);
+
+ callbacksEnabled = NSK_FALSE;
jvmti->RawMonitorExit(agent_lock);
}
@@ -261,12 +278,15 @@
callbacks.Breakpoint = &Breakpoint;
callbacks.SingleStep = &SingleStep;
callbacks.VMStart = &VMStart;
+ callbacks.VMDeath = &VMDeath;
if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks))))
return JNI_ERR;
NSK_DISPLAY0("setting event callbacks done\nenabling JVMTI events ...\n");
if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_START, NULL)))
return JNI_ERR;
+ if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL)))
+ return JNI_ERR;
if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL)))
return JNI_ERR;
if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, NULL)))
--- a/test/jdk/ProblemList.txt Tue Apr 09 16:11:54 2019 -0400
+++ b/test/jdk/ProblemList.txt Thu Apr 11 07:44:51 2019 -0400
@@ -158,12 +158,39 @@
java/awt/Mixing/AWT_Mixing/MixingPanelsResizing.java 8049405 generic-all
java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java 8049405 macosx-all
java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java 8049405 macosx-all
+java/awt/Mixing/AWT_Mixing/JButtonInGlassPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JButtonOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JColorChooserOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JEditorPaneInGlassPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JEditorPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JLabelInGlassPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JLabelOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JListInGlassPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JListOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JPanelInGlassPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JPanelOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JProgressBarInGlassPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JProgressBarOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JScrollBarInGlassPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JScrollBarOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JSliderInGlassPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JSliderOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JSpinnerInGlassPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JSpinnerOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JTableInGlassPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JTableOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JTextAreaInGlassPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JTextAreaOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JTextFieldInGlassPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JTextFieldOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JToggleButtonInGlassPaneOverlapping.java 8158801 windows-all
+java/awt/Mixing/AWT_Mixing/JToggleButtonOverlapping.java 8158801 windows-all
java/awt/Mixing/NonOpaqueInternalFrame.java 7124549 macosx-all
java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowRetaining.java 6829264 generic-all
java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java 8080982 generic-all
java/awt/datatransfer/SystemFlavorMap/AddFlavorTest.java 8079268 linux-all
java/awt/Toolkit/ScreenInsetsTest/ScreenInsetsTest.java 6829250 windows-all
-java/awt/Toolkit/RealSync/Test.java 6849383 macosx-all
+java/awt/Toolkit/RealSync/Test.java 6849383 macosx-all,linux-all
java/awt/LightweightComponent/LightweightEventTest/LightweightEventTest.java 8159252 windows-all
java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java 8203047 macosx-all
java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.java 8073636 macosx-all
@@ -212,6 +239,7 @@
java/awt/Window/ShapedAndTranslucentWindows/ShapedTranslucent.java 8078999 macosx-all
java/awt/Window/ShapedAndTranslucentWindows/ShapedTranslucentWindowClick.java 8013450 macosx-all
java/awt/Window/ShapedAndTranslucentWindows/StaticallyShaped.java 8165218 macosx-all,linux-all
+java/awt/Window/ShapedAndTranslucentWindows/TranslucentChoice.java 8221901 linux-all
java/awt/Window/AlwaysOnTop/AutoTestOnTop.java 6847593 macosx-all
java/awt/Window/GrabSequence/GrabSequence.java 6848409 macosx-all,linux-all
java/awt/Window/LocationAtScreenCorner/LocationAtScreenCorner.java 8203371 linux-all,solaris-all
@@ -242,6 +270,7 @@
sun/java2d/SunGraphics2D/SimplePrimQuality.java 6992007 generic-all
sun/java2d/SunGraphics2D/SourceClippingBlitTest/SourceClippingBlitTest.java 8196185 generic-all
sun/java2d/pipe/InterpolationQualityTest.java 8171303 windows-all,linux-all,macosx-all
+sun/java2d/X11SurfaceData/SharedMemoryPixmapsTest/SharedMemoryPixmapsTest.sh 8221451 linux-all
java/awt/FullScreen/DisplayChangeVITest/DisplayChangeVITest.java 8169469 windows-all
java/awt/Graphics2D/DrawString/DrawRotatedStringUsingRotatedFont.java 8197796 generic-all
java/awt/TextArea/TextAreaScrolling/TextAreaScrolling.java 8196300 windows-all
@@ -249,6 +278,7 @@
java/awt/print/PrinterJob/GlyphPositions.java 7003378 generic-all
java/awt/Choice/PopupPosTest/PopupPosTest.java 8197811 windows-all
java/awt/Choice/ChoiceMouseWheelTest/ChoiceMouseWheelTest.java 7100044 macosx-all,linux-all
+java/awt/Choice/ChoiceKeyEventReaction/ChoiceKeyEventReaction.java 8214469 macosx-all
java/awt/Component/CreateImage/CreateImage.java 8198334 windows-all
java/awt/Component/GetScreenLocTest/GetScreenLocTest.java 4753654 generic-all
java/awt/Clipboard/HTMLTransferTest/HTMLTransferTest.java 8017454 macosx-all
@@ -395,6 +425,7 @@
java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Standard.java 7124407 macosx-all
java/awt/Mouse/RemovedComponentMouseListener/RemovedComponentMouseListener.java 8157170 macosx-all
java/awt/Modal/ToFront/DialogToFrontModeless1Test.java 8213530 linux-all
+java/awt/Modal/ToFront/DialogToFrontNonModalTest.java 8221899 linux-all
java/awt/Modal/ToBack/ToBackAppModal1Test.java 8196441 linux-all,macosx-all
java/awt/Modal/ToBack/ToBackAppModal2Test.java 8196441 linux-all,macosx-all
java/awt/Modal/ToBack/ToBackAppModal3Test.java 8196441 linux-all,macosx-all
@@ -699,6 +730,7 @@
javax/sound/sampled/Mixers/DisabledAssertionCrash.java 7067310 generic-all
javax/sound/midi/Sequencer/Recording.java 8167580 linux-all,solaris-all
+javax/sound/midi/Sequencer/MetaCallback.java 8178698 linux-all,solaris-all
############################################################################
@@ -810,6 +842,8 @@
javax/swing/JTable/6263446/bug6263446.java 8169959 macosx-all
javax/swing/JTree/6263446/bug6263446.java 8213125 macosx-all
javax/swing/JTree/8003400/Test8003400.java 8197560 macosx-all,linux-all
+javax/swing/RepaintManager/IconifyTest/IconifyTest.java 8221903 linux-all
+javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java 8221902 linux-all
############################################################################
--- a/test/jdk/java/awt/print/RemotePrinterStatusRefresh/RemotePrinterStatusRefresh.java Tue Apr 09 16:11:54 2019 -0400
+++ b/test/jdk/java/awt/print/RemotePrinterStatusRefresh/RemotePrinterStatusRefresh.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* 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,244 +21,480 @@
* questions.
*/
-/**
+/*
* @test
- * @bug 8153732 8212202
+ * @bug 8153732 8212202 8221263 8221412
* @requires (os.family == "Windows")
* @summary Windows remote printer changes do not reflect in lookupPrintServices()
- * @ignore Requires a new network printer installation\removal
* @run main/manual RemotePrinterStatusRefresh
*/
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.GridLayout;
import java.awt.event.ActionEvent;
-import java.awt.print.PageFormat;
-import java.awt.print.Paper;
-import java.awt.print.PrinterException;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
+import javax.print.PrintService;
+import javax.print.PrintServiceLookup;
+import javax.swing.AbstractListModel;
import javax.swing.BorderFactory;
import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
+import javax.swing.JList;
import javax.swing.JPanel;
+import javax.swing.JScrollPane;
import javax.swing.JTextArea;
+import javax.swing.JTextField;
import javax.swing.SwingUtilities;
-import java.awt.print.PrinterJob;
-import javax.print.PrintService;
+import javax.swing.Timer;
+
+import static javax.swing.BorderFactory.createTitledBorder;
+
+public class RemotePrinterStatusRefresh extends WindowAdapter {
+
+ private static final long refreshTime = getRefreshTime();
+
+ private static final long TIMEOUT = refreshTime * 4 + 60;
+
-public class RemotePrinterStatusRefresh
-{
- private static TestUI test = null;
- public static void main(String args[]) throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
+ private static final CountDownLatch latch = new CountDownLatch(1);
+ private static volatile RemotePrinterStatusRefresh test;
+
+ private volatile boolean testResult;
+ private volatile boolean testTimedOut;
+
+ private final JFrame frame;
- // Test UI creation
- test = new TestUI(latch);
+ private JButton refreshButton;
+ private JButton passButton;
+ private JButton failButton;
+
+ private final ServiceItemListModel beforeList;
+ private final ServiceItemListModel afterList;
+
+ private JTextField nextRefresh;
+ private JTextField timeLeft;
+
+ private final Timer timer;
+ private final long startTime;
+
- SwingUtilities.invokeAndWait(new Runnable() {
- @Override
- public void run() {
- try {
- test.createUI();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- });
+ private static class ServiceItem {
+ private enum State {
+ REMOVED, UNCHANGED, ADDED
+ }
+
+ final String name;
+ State state;
+
+ private ServiceItem(final String name) {
+ this.name = name;
+ state = State.UNCHANGED;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
- // RemotePrinterStatusRefresh creation
- RemotePrinterStatusRefresh RemotePrinterStatusRefresh = new RemotePrinterStatusRefresh();
- SwingUtilities.invokeAndWait(() -> {
- collectPrintersList(test.resultsTextArea, true);
- });
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof ServiceItem)
+ && ((ServiceItem) obj).name.equals(name);
+ }
- // 8 min = 480000 msec
- if(waitForFlag(480000)) {
- SwingUtilities.invokeAndWait(() -> {
- collectPrintersList(test.resultsTextArea, false);
- });
- } else {
- dispose();
- throw new RuntimeException("No new network printer got added/removed!! Test timed out!!");
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+ }
+
+ private static class ServiceItemListModel extends AbstractListModel<ServiceItem> {
+ private final List<ServiceItem> list;
+
+ private ServiceItemListModel(List<ServiceItem> list) {
+ this.list = list;
+ }
+
+ @Override
+ public int getSize() {
+ return list.size();
}
- boolean status = latch.await(1, TimeUnit.MINUTES);
- if (!status) {
- dispose();
- throw new RuntimeException("Test timed out.");
+ @Override
+ public ServiceItem getElementAt(int index) {
+ return list.get(index);
+ }
+
+ private void refreshList(List<ServiceItem> newList) {
+ list.clear();
+ list.addAll(newList);
+ fireChanged();
}
- if (test.testResult == false) {
- dispose();
- throw new RuntimeException("Test Failed.");
+ private void fireChanged() {
+ fireContentsChanged(this, 0, list.size() - 1);
}
+ }
- dispose();
+ private static class ServiceItemListRenderer extends DefaultListCellRenderer {
+ @Override
+ public Component getListCellRendererComponent(JList<?> list,
+ Object value,
+ int index,
+ boolean isSelected,
+ boolean cellHasFocus) {
+ Component component =
+ super.getListCellRendererComponent(list, value, index,
+ isSelected, cellHasFocus);
+ switch (((ServiceItem) value).state) {
+ case REMOVED:
+ component.setBackground(Color.RED);
+ component.setForeground(Color.WHITE);
+ break;
+ case ADDED:
+ component.setBackground(Color.GREEN);
+ component.setForeground(Color.BLACK);
+ break;
+ case UNCHANGED:
+ default:
+ break;
+ }
+ return component;
+ }
}
- public static void dispose() throws Exception {
- SwingUtilities.invokeAndWait(() -> {
- test.disposeUI();
- });
+ private static final String INSTRUCTIONS_TEXT =
+ "Please follow the steps for this manual test:\n"
+ + "Step 0: \"Before\" list is populated with currently "
+ + "configured printers.\n"
+ + "Step 1: Add or Remove a network printer using "
+ + "Windows Control Panel.\n"
+ + "Step 2: Wait for 4 minutes after adding or removing.\n"
+ + " \"Next printer refresh in\" gives you a "
+ + "rough estimation on when update will happen.\n"
+ + "Step 3: Click Refresh."
+ + "\"After\" list is populated with updated list "
+ + "of printers.\n"
+ + "Step 4: Compare the list of printers in \"Before\" and "
+ + "\"After\" lists.\n"
+ + " Added printers are highlighted with "
+ + "green color, removed ones \u2014 with "
+ + "red color.\n"
+ + "Step 5: Click Pass if the list of printers is correctly "
+ + "updated.\n"
+ + "Step 6: If the list is not updated, wait for another "
+ + "4 minutes, and then click Refresh again.\n"
+ + "Step 7: If the list does not update, click Fail.\n"
+ + "\n"
+ + "You have to click Refresh to enable Pass and Fail buttons. "
+ + "If no button is pressed,\n"
+ + "the test will time out. "
+ + "Closing the window also fails the test.";
+
+ public static void main(String[] args) throws Exception {
+ SwingUtilities.invokeAndWait(RemotePrinterStatusRefresh::createUI);
+
+ latch.await();
+ if (!test.testResult) {
+ throw new RuntimeException("Test failed"
+ + (test.testTimedOut ? " because of time out" : ""));
+ }
}
- public static boolean waitForFlag (long maxTimeoutInMsec) throws Exception {
- while(!test.isAdded && maxTimeoutInMsec > 0) {
- maxTimeoutInMsec -= 100;
- Thread.sleep(100);
- }
-
- if(maxTimeoutInMsec <= 0) {
- return false;
- } else {
- return true;
+ private static long getRefreshTime() {
+ String refreshTime =
+ System.getProperty("sun.java2d.print.minRefreshTime", "240");
+ try {
+ long value = Long.parseLong(refreshTime);
+ return value < 240L ? 240L : value;
+ } catch (NumberFormatException e) {
+ return 240L;
}
}
- private static void collectPrintersList(JTextArea textArea, boolean before) {
- if(before) {
- System.out.println("List of printers(before): ");
- textArea.setText("List of printers(before): \n");
- for (PrintService printServiceBefore : PrinterJob.lookupPrintServices()) {
- System.out.println(printServiceBefore);
- textArea.append(printServiceBefore.toString());
- textArea.append("\n");
- }
- } else {
- textArea.append("\n");
- System.out.println("List of printers(after): ");
- textArea.append("List of printers(after): \n");
- for (PrintService printServiceAfter : PrinterJob.lookupPrintServices()) {
- System.out.println(printServiceAfter);
- textArea.append(printServiceAfter.toString());
- textArea.append("\n");
- }
- }
+ private static void createUI() {
+ test = new RemotePrinterStatusRefresh();
}
-}
+
+ private RemotePrinterStatusRefresh() {
+ frame = new JFrame("RemotePrinterStatusRefresh");
+ frame.addWindowListener(this);
+
+
+ JPanel northPanel = new JPanel(new BorderLayout());
+ northPanel.add(createInfoPanel(), BorderLayout.NORTH);
+ northPanel.add(createInstructionsPanel(), BorderLayout.SOUTH);
+
+
+ beforeList = new ServiceItemListModel(
+ Collections.unmodifiableList(collectPrinterList()));
+ afterList = new ServiceItemListModel(new ArrayList<>());
+ logList("Before:", beforeList.list);
+
+ JPanel listPanel = new JPanel(new GridLayout(1, 2));
+ listPanel.setBorder(createTitledBorder("Print Services"));
+ listPanel.add(createListPanel(beforeList, "Before:", 'b'));
+ listPanel.add(createListPanel(afterList, "After:", 'a'));
+
+
+ JPanel mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(northPanel, BorderLayout.NORTH);
+ mainPanel.add(listPanel, BorderLayout.CENTER);
+ mainPanel.add(createButtonPanel(), BorderLayout.SOUTH);
+
+
+ frame.add(mainPanel);
+ frame.pack();
+ refreshButton.requestFocusInWindow();
+ frame.setVisible(true);
+
+
+ timer = new Timer(1000, this::updateTimeLeft);
+ timer.start();
+ startTime = System.currentTimeMillis();
+ updateTimeLeft(null);
+ }
+
+ private JPanel createInfoPanel() {
+ JLabel javaLabel = new JLabel("Java version:");
+ JTextField javaVersion =
+ new JTextField(System.getProperty("java.runtime.version"));
+ javaVersion.setEditable(false);
+ javaLabel.setLabelFor(javaVersion);
-class TestUI {
- private static JFrame mainFrame;
- private static JPanel mainControlPanel;
+ JLabel refreshTimeLabel = new JLabel("Refresh interval:");
+ long minutes = refreshTime / 60;
+ long seconds = refreshTime % 60;
+ String interval = String.format("%1$d seconds%2$s",
+ refreshTime,
+ minutes > 0
+ ? String.format(" (%1$d %2$s%3$s)",
+ minutes,
+ minutes > 1 ? "minutes" : "minute",
+ seconds > 0
+ ? String.format(" %1$d %2$s",
+ seconds,
+ seconds > 1 ? "seconds" : "second")
+ : "")
+ : ""
+ );
+ JTextField refreshInterval = new JTextField(interval);
+ refreshInterval.setEditable(false);
+ refreshTimeLabel.setLabelFor(refreshInterval);
- private static JTextArea instructionTextArea;
+ JLabel nextRefreshLabel = new JLabel("Next printer refresh in:");
+ nextRefresh = new JTextField();
+ nextRefresh.setEditable(false);
+ nextRefreshLabel.setLabelFor(nextRefresh);
- private static JPanel resultButtonPanel;
- private static JButton passButton;
- private static JButton failButton;
- private static JButton addedButton;
+ JLabel timeoutLabel = new JLabel("Time left:");
+ timeLeft = new JTextField();
+ timeLeft.setEditable(false);
+ timeoutLabel.setLabelFor(timeLeft);
- private static JPanel testPanel;
- private static JButton testButton;
- private static JLabel buttonPressCountLabel;
+ JPanel infoPanel = new JPanel();
+ GroupLayout layout = new GroupLayout(infoPanel);
+ infoPanel.setLayout(layout);
+ infoPanel.setBorder(BorderFactory.createTitledBorder("Info"));
+ layout.setAutoCreateGaps(true);
+ layout.setHorizontalGroup(
+ layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(javaLabel)
+ .addComponent(refreshTimeLabel)
+ .addComponent(nextRefreshLabel)
+ .addComponent(timeoutLabel)
+ )
+ .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, true)
+ .addComponent(javaVersion)
+ .addComponent(refreshInterval)
+ .addComponent(nextRefresh)
+ .addComponent(timeLeft)
+ )
+ );
+ layout.setVerticalGroup(
+ layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(javaLabel)
+ .addComponent(javaVersion)
+ )
+ .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(refreshTimeLabel)
+ .addComponent(refreshInterval))
+ .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(nextRefreshLabel)
+ .addComponent(nextRefresh))
+ .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(timeoutLabel)
+ .addComponent(timeLeft))
+ );
+ return infoPanel;
+ }
- private static GridBagLayout layout;
- private final CountDownLatch latch;
- public boolean testResult = false;
- public volatile Boolean isAdded = false;
- public static JTextArea resultsTextArea;
-
- public TestUI(CountDownLatch latch) throws Exception {
- this.latch = latch;
+ private JPanel createInstructionsPanel() {
+ JPanel instructionsPanel = new JPanel(new BorderLayout());
+ JTextArea instructionText = new JTextArea(INSTRUCTIONS_TEXT);
+ instructionText.setEditable(false);
+ instructionsPanel.setBorder(createTitledBorder("Test Instructions"));
+ instructionsPanel.add(new JScrollPane(instructionText));
+ return instructionsPanel;
}
- public final void createUI() {
- mainFrame = new JFrame("RemotePrinterStatusRefresh");
- layout = new GridBagLayout();
- mainControlPanel = new JPanel(layout);
- resultButtonPanel = new JPanel(layout);
- testPanel = new JPanel(layout);
- GridBagConstraints gbc = new GridBagConstraints();
-
- // Create Test instructions
- String instructions
- = "This test displays the current list of printers(before) attached to \n"
- + "this computer in the results panel.\n\n"
- + "Please follow the below steps for this manual test\n"
- + "--------------------------------------------------------------------\n"
- + "Step 1: Add/Remove a new network printer and Wait for 4 minutes after adding/removing\n"
- + "Step 2: Then click on 'Printer Added/Removed' button\n"
- + "Step 2: Once the new network printer is added/removed, see if it is \n"
- + " the same as displayed/not displayed in the results panel.\n"
- + "Step 3: If displayed/not displayed, then click 'Pass' else click on 'Fail' button";
-
- instructionTextArea = new JTextArea();
- instructionTextArea.setText(instructions);
- instructionTextArea.setEditable(false);
- instructionTextArea.setBorder(BorderFactory.
- createTitledBorder("Test Instructions"));
+ private JPanel createListPanel(final ServiceItemListModel model,
+ final String title,
+ final char mnemonic) {
+ JPanel panel = new JPanel();
+ panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+ JList<ServiceItem> list = new JList<>(model);
+ list.setCellRenderer(new ServiceItemListRenderer());
- gbc.gridx = 0;
- gbc.gridy = 0;
- gbc.fill = GridBagConstraints.HORIZONTAL;
- mainControlPanel.add(instructionTextArea, gbc);
-
- gbc.gridx = 0;
- gbc.gridy = 1;
- testPanel.add(Box.createVerticalStrut(50));
- mainControlPanel.add(testPanel);
+ JLabel label = new JLabel(title);
+ label.setLabelFor(list);
+ label.setDisplayedMnemonic(mnemonic);
+ JPanel labelPanel = new JPanel();
+ labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.X_AXIS));
+ labelPanel.add(label, BorderLayout.EAST);
+ labelPanel.add(Box.createHorizontalGlue());
- addedButton = new JButton("Printer Added/Removed");
- addedButton.setActionCommand("Added");
- addedButton.addActionListener((ActionEvent e) -> {
- System.out.println("Added Button pressed!");
- isAdded = true;
- });
+ panel.add(labelPanel);
+ panel.add(new JScrollPane(list));
+ return panel;
+ }
- // Create resultButtonPanel with Pass, Fail buttons
+ private JPanel createButtonPanel() {
+ refreshButton = new JButton("Refresh");
+ refreshButton.addActionListener(this::refresh);
+
passButton = new JButton("Pass");
- passButton.setActionCommand("Pass");
- passButton.addActionListener((ActionEvent e) -> {
- System.out.println("Pass Button pressed!");
- testResult = true;
- latch.countDown();
- disposeUI();
- });
+ passButton.addActionListener(this::pass);
+ passButton.setEnabled(false);
failButton = new JButton("Fail");
- failButton.setActionCommand("Fail");
- failButton.addActionListener((ActionEvent e) -> {
- System.out.println("Fail Button pressed!");
- testResult = false;
- latch.countDown();
- disposeUI();
- });
+ failButton.addActionListener(this::fail);
+ failButton.setEnabled(false);
- gbc.gridx = 0;
- gbc.gridy = 0;
- resultButtonPanel.add(addedButton, gbc);
-
- gbc.gridx = 1;
- gbc.gridy = 0;
- resultButtonPanel.add(passButton, gbc);
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
+ buttonPanel.add(Box.createHorizontalGlue());
+ buttonPanel.add(refreshButton);
+ buttonPanel.add(passButton);
+ buttonPanel.add(failButton);
+ buttonPanel.add(Box.createHorizontalGlue());
+ return buttonPanel;
+ }
- gbc.gridx = 2;
- gbc.gridy = 0;
- resultButtonPanel.add(failButton, gbc);
-
- resultsTextArea = new JTextArea();
- resultsTextArea.setEditable(false);
- resultsTextArea.setBorder(BorderFactory.
- createTitledBorder("Results"));
+ private static List<ServiceItem> collectPrinterList() {
+ PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);
+ List<ServiceItem> list = new ArrayList<>(printServices.length);
+ for (PrintService service : printServices) {
+ list.add(new ServiceItem(service.getName()));
+ }
+ return list;
+ }
- gbc.gridx = 0;
- gbc.gridy = 1;
- gbc.fill = GridBagConstraints.HORIZONTAL;
- mainControlPanel.add(resultsTextArea, gbc);
-
- gbc.gridx = 0;
- gbc.gridy = 2;
- mainControlPanel.add(resultButtonPanel, gbc);
-
- mainFrame.add(mainControlPanel);
- mainFrame.pack();
- mainFrame.setVisible(true);
+ private static void logList(final String title, final List<ServiceItem> list) {
+ System.out.println(title);
+ for (ServiceItem item : list) {
+ System.out.println(item.name);
+ }
+ System.out.println();
}
- public void disposeUI() {
- mainFrame.dispose();
+ private static void compareLists(final ServiceItemListModel before, final ServiceItemListModel after) {
+ boolean beforeUpdated = false;
+ boolean afterUpdated = false;
+
+ for (ServiceItem item : before.list) {
+ if (!after.list.contains(item)) {
+ item.state = ServiceItem.State.REMOVED;
+ beforeUpdated = true;
+ } else if (item.state != ServiceItem.State.UNCHANGED) {
+ item.state = ServiceItem.State.UNCHANGED;
+ beforeUpdated = true;
+ }
+ }
+
+ for (ServiceItem item : after.list) {
+ if (!before.list.contains(item)) {
+ item.state = ServiceItem.State.ADDED;
+ afterUpdated = true;
+ } else if (item.state != ServiceItem.State.UNCHANGED) {
+ item.state = ServiceItem.State.UNCHANGED;
+ afterUpdated = true;
+ }
+ }
+
+ if (beforeUpdated) {
+ before.fireChanged();
+ }
+ if (afterUpdated) {
+ after.fireChanged();
+ }
+ }
+
+ @Override
+ public void windowClosing(WindowEvent e) {
+ System.out.println("The window closed");
+ disposeUI();
+ }
+
+ private void disposeUI() {
+ timer.stop();
+ latch.countDown();
+ frame.dispose();
}
+
+ @SuppressWarnings("unused")
+ private void refresh(ActionEvent e) {
+ System.out.println("Refresh button pressed");
+ afterList.refreshList(collectPrinterList());
+ compareLists(beforeList, afterList);
+ passButton.setEnabled(true);
+ failButton.setEnabled(true);
+ logList("After:", afterList.list);
+ }
+
+ @SuppressWarnings("unused")
+ private void pass(ActionEvent e) {
+ System.out.println("Pass button pressed");
+ testResult = true;
+ disposeUI();
+ }
+
+ @SuppressWarnings("unused")
+ private void fail(ActionEvent e) {
+ System.out.println("Fail button pressed");
+ testResult = false;
+ disposeUI();
+ }
+
+ @SuppressWarnings("unused")
+ private void updateTimeLeft(ActionEvent e) {
+ long elapsed = (System.currentTimeMillis() - startTime) / 1000;
+ long left = TIMEOUT - elapsed;
+ if (left < 0) {
+ testTimedOut = true;
+ disposeUI();
+ }
+ timeLeft.setText(formatTime(left));
+ nextRefresh.setText(formatTime(refreshTime - (elapsed % refreshTime)));
+ }
+
+ private static String formatTime(final long seconds) {
+ long minutes = seconds / 60;
+ return String.format("%d:%02d", minutes, seconds - minutes * 60);
+ }
+
}
--- a/test/jdk/java/lang/Math/DivModTests.java Tue Apr 09 16:11:54 2019 -0400
+++ b/test/jdk/java/lang/Math/DivModTests.java Thu Apr 11 07:44:51 2019 -0400
@@ -91,6 +91,10 @@
testIntFloorDivMod(Integer.MIN_VALUE, 3, -715827883, 1);
testIntFloorDivMod(Integer.MIN_VALUE + 1, 3, -715827883, 2);
testIntFloorDivMod(Integer.MIN_VALUE + 1, -1, Integer.MAX_VALUE, 0);
+ testIntFloorDivMod(Integer.MAX_VALUE, Integer.MAX_VALUE, 1, 0);
+ testIntFloorDivMod(Integer.MAX_VALUE, Integer.MIN_VALUE, -1, -1);
+ testIntFloorDivMod(Integer.MIN_VALUE, Integer.MIN_VALUE, 1, 0);
+ testIntFloorDivMod(Integer.MIN_VALUE, Integer.MAX_VALUE, -2, 2147483646);
// Special case of integer overflow
testIntFloorDivMod(Integer.MIN_VALUE, -1, Integer.MIN_VALUE, 0);
}
@@ -179,6 +183,10 @@
testLongFloorDivMod(Long.MIN_VALUE, 3L, Long.MIN_VALUE / 3L - 1L, 1L);
testLongFloorDivMod(Long.MIN_VALUE + 1L, 3L, Long.MIN_VALUE / 3L - 1L, 2L);
testLongFloorDivMod(Long.MIN_VALUE + 1, -1, Long.MAX_VALUE, 0L);
+ testLongFloorDivMod(Long.MAX_VALUE, Long.MAX_VALUE, 1L, 0L);
+ testLongFloorDivMod(Long.MAX_VALUE, Long.MIN_VALUE, -1L, -1L);
+ testLongFloorDivMod(Long.MIN_VALUE, Long.MIN_VALUE, 1L, 0L);
+ testLongFloorDivMod(Long.MIN_VALUE, Long.MAX_VALUE, -2L, 9223372036854775806L);
// Special case of integer overflow
testLongFloorDivMod(Long.MIN_VALUE, -1, Long.MIN_VALUE, 0L);
}
@@ -283,6 +291,10 @@
testLongIntFloorDivMod(Long.MIN_VALUE, 3, Long.MIN_VALUE / 3L - 1L, 1L);
testLongIntFloorDivMod(Long.MIN_VALUE + 1L, 3, Long.MIN_VALUE / 3L - 1L, 2L);
testLongIntFloorDivMod(Long.MIN_VALUE + 1, -1, Long.MAX_VALUE, 0L);
+ testLongIntFloorDivMod(Long.MAX_VALUE, Integer.MAX_VALUE, 4294967298L, 1);
+ testLongIntFloorDivMod(Long.MAX_VALUE, Integer.MIN_VALUE, -4294967296L, -1);
+ testLongIntFloorDivMod(Long.MIN_VALUE, Integer.MIN_VALUE, 4294967296L, 0);
+ testLongIntFloorDivMod(Long.MIN_VALUE, Integer.MAX_VALUE, -4294967299L, 2147483645);
// Special case of integer overflow
testLongIntFloorDivMod(Long.MIN_VALUE, -1, Long.MIN_VALUE, 0L);
}
--- a/test/jdk/java/lang/StringBuffer/CompactStringBuffer.java Tue Apr 09 16:11:54 2019 -0400
+++ b/test/jdk/java/lang/StringBuffer/CompactStringBuffer.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* 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 @@
/*
* @test
- * @bug 8077559
+ * @bug 8077559 8221430
* @summary Tests Compact String. This test is testing StringBuffer
* behavior related to Compact String.
* @run testng/othervm -XX:+CompactStrings CompactStringBuffer
@@ -440,6 +440,12 @@
"abcdefgh1.23456");
check(new StringBuffer().append(bmp).append(1.23456).toString(),
"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e081.23456");
+
+ ////////////////////////////////////////////////////////////////////
+ check(new StringBuffer((CharSequence)new StringBuffer(ascii)).toString(),
+ ascii);
+ check(new StringBuffer((CharSequence)new StringBuffer(asciiMixed)).toString(),
+ asciiMixed);
}
private void checkGetChars(StringBuffer sb, int srcBegin, int srcEnd,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/security/Signature/SignatureGetInstance.java Thu Apr 11 07:44:51 2019 -0400
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * 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 8216039
+ * @summary Ensure the BC provider-reselection workaround in Signature class
+ * functions correctly
+ * @modules java.base/sun.security.util
+ * @run main/othervm SignatureGetInstance
+ */
+import java.security.*;
+import java.security.interfaces.*;
+import java.security.spec.*;
+import sun.security.util.SignatureUtil;
+
+public class SignatureGetInstance {
+
+ private static final String SIGALG = "RSASSA-PSS";
+
+ public static void main(String[] args) throws Exception {
+ Provider testProvider = new TestProvider();
+ // put test provider before SunRsaSign provider
+ Security.insertProviderAt(testProvider, 1);
+ //Security.addProvider(testProvider);
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ KeyPair kp = kpg.generateKeyPair();
+
+ MyPrivKey testPriv = new MyPrivKey();
+ MyPubKey testPub = new MyPubKey();
+
+ testDblInit(testPriv, testPub, true, "TestProvider");
+ testDblInit(kp.getPrivate(), kp.getPublic(), true, "SunRsaSign");
+ testDblInit(testPriv, kp.getPublic(), false, null);
+ testDblInit(kp.getPrivate(), testPub, false, null);
+
+ testSetAndInit(null, testPriv, true);
+ testSetAndInit(null, testPub, true);
+ testSetAndInit(null, kp.getPrivate(), true);
+ testSetAndInit(null, kp.getPublic(), true);
+
+ String provName = "SunRsaSign";
+ testSetAndInit(provName, testPriv, false);
+ testSetAndInit(provName, testPub, false);
+ testSetAndInit(provName, kp.getPrivate(), true);
+ testSetAndInit(provName, kp.getPublic(), true);
+
+ provName = "TestProvider";
+ testSetAndInit(provName, testPriv, true);
+ testSetAndInit(provName, testPub, true);
+ testSetAndInit(provName, kp.getPrivate(), false);
+ testSetAndInit(provName, kp.getPublic(), false);
+
+ System.out.println("Test Passed");
+ }
+
+ private static void checkName(Signature s, String name) {
+ if (name != null &&
+ !(name.equals(s.getProvider().getName()))) {
+ throw new RuntimeException("Fail: provider name mismatch");
+ }
+ }
+
+ private static void testDblInit(PrivateKey key1, PublicKey key2,
+ boolean shouldPass, String expectedProvName) throws Exception {
+ Signature sig = Signature.getInstance(SIGALG);
+ SignatureUtil.initSignWithParam(sig, key1, PSSParameterSpec.DEFAULT, null);
+ try {
+ sig.initVerify(key2);
+ if (!shouldPass) {
+ throw new RuntimeException("Fail: should throw InvalidKeyException");
+ }
+ checkName(sig, expectedProvName);
+ } catch (InvalidKeyException ike) {
+ if (shouldPass) {
+ System.out.println("Fail: Unexpected InvalidKeyException");
+ throw ike;
+ }
+ }
+ }
+
+ private static void testSetAndInit(String provName, Key key,
+ boolean shouldPass) throws Exception {
+ Signature sig;
+ if (provName == null) {
+ sig = Signature.getInstance(SIGALG);
+ } else {
+ sig = Signature.getInstance(SIGALG, provName);
+ }
+ AlgorithmParameterSpec params = PSSParameterSpec.DEFAULT;
+ boolean doSign = (key instanceof PrivateKey);
+ try {
+ if (doSign) {
+ SignatureUtil.initSignWithParam(sig, (PrivateKey)key, params, null);
+ } else {
+ SignatureUtil.initVerifyWithParam(sig, (PublicKey)key, params);
+ }
+ if (!shouldPass) {
+ throw new RuntimeException("Fail: should throw InvalidKeyException");
+ }
+ checkName(sig, provName);
+ // check that the earlier parameter is still there
+ if (sig.getParameters() == null) {
+ throw new RuntimeException("Fail: parameters not preserved");
+ }
+ } catch (InvalidKeyException ike) {
+ if (shouldPass) {
+ System.out.println("Fail: Unexpected InvalidKeyException");
+ throw ike;
+ }
+ }
+ }
+
+ // Test provider which only accepts its own Key objects
+ // Registered to be more preferred than SunRsaSign provider
+ // for testing deferred provider selection
+ public static class TestProvider extends Provider {
+ TestProvider() {
+ super("TestProvider", "1.0", "provider for SignatureGetInstance");
+ put("Signature.RSASSA-PSS",
+ "SignatureGetInstance$MySigImpl");
+ }
+ }
+
+ public static class MyPrivKey implements PrivateKey {
+ public String getAlgorithm() { return "RSASSA-PSS"; }
+ public String getFormat() { return "MyOwn"; }
+ public byte[] getEncoded() { return null; }
+ }
+
+ public static class MyPubKey implements PublicKey {
+ public String getAlgorithm() { return "RSASSA-PSS"; }
+ public String getFormat() { return "MyOwn"; }
+ public byte[] getEncoded() { return null; }
+ }
+
+ public static class MySigImpl extends SignatureSpi {
+ // simulate BC behavior of only using params set before init calls
+ AlgorithmParameterSpec initParamSpec = null;
+ AlgorithmParameterSpec paramSpec = null;
+
+ public MySigImpl() {
+ super();
+ }
+
+ @Override
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException {
+ if (!(publicKey instanceof MyPubKey)) {
+ throw new InvalidKeyException("Must be MyPubKey");
+ }
+ initParamSpec = paramSpec;
+ }
+
+ @Override
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException {
+ if (!(privateKey instanceof MyPrivKey)) {
+ throw new InvalidKeyException("Must be MyPrivKey");
+ }
+ initParamSpec = paramSpec;
+ }
+
+ @Override
+ protected void engineUpdate(byte b) throws SignatureException {
+ }
+
+ @Override
+ protected void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException {
+ }
+
+ @Override
+ protected byte[] engineSign()
+ throws SignatureException {
+ return new byte[0];
+ }
+
+ @Override
+ protected boolean engineVerify(byte[] sigBytes)
+ throws SignatureException {
+ return false;
+ }
+
+ @Override
+ @Deprecated
+ protected void engineSetParameter(String param, Object value)
+ throws InvalidParameterException {
+ }
+
+ @Override
+ protected void engineSetParameter(AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException {
+ paramSpec = params;
+ }
+
+ @Override
+ @Deprecated
+ protected AlgorithmParameters engineGetParameter(String param)
+ throws InvalidParameterException {
+ return null;
+ }
+
+ @Override
+ protected AlgorithmParameters engineGetParameters() {
+ if (initParamSpec != null) {
+ try {
+ AlgorithmParameters ap =
+ AlgorithmParameters.getInstance("RSASSA-PSS");
+ ap.init(initParamSpec);
+ return ap;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return null;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/sound/midi/SysexMessage/Basic.java Thu Apr 11 07:44:51 2019 -0400
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * 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.Arrays;
+
+import javax.sound.midi.SysexMessage;
+
+import static javax.sound.midi.SysexMessage.SPECIAL_SYSTEM_EXCLUSIVE;
+import static javax.sound.midi.SysexMessage.SYSTEM_EXCLUSIVE;
+
+/**
+ * @test
+ * @bug 8221445
+ * @summary Checks basic functionality of javax.sound.midi.SysexMessage class
+ */
+public class Basic {
+
+ public static void main(final String[] args) throws Exception {
+ byte[] dataExclusive = {(byte) (SYSTEM_EXCLUSIVE)};
+ byte[] dataSpecialExclusive = {(byte) (SPECIAL_SYSTEM_EXCLUSIVE)};
+ byte[] empty = {};
+
+ ////////////////////////////
+ // Constructors
+ ////////////////////////////
+ SysexMessage msg = new SysexMessage(dataExclusive, 1);
+ test(msg, SYSTEM_EXCLUSIVE, empty, 1);
+ msg = new SysexMessage(dataSpecialExclusive, 1);
+ test(msg, SPECIAL_SYSTEM_EXCLUSIVE, empty, 1);
+ msg = new SysexMessage(SYSTEM_EXCLUSIVE, empty, 0);
+ test(msg, SYSTEM_EXCLUSIVE, empty, 1);
+ msg = new SysexMessage(SPECIAL_SYSTEM_EXCLUSIVE, empty, 0);
+ test(msg, SPECIAL_SYSTEM_EXCLUSIVE, empty, 1);
+ msg = new SysexMessage(SYSTEM_EXCLUSIVE, dataSpecialExclusive, 1);
+ test(msg, SYSTEM_EXCLUSIVE, dataSpecialExclusive, 2);
+ msg = new SysexMessage(SPECIAL_SYSTEM_EXCLUSIVE, dataExclusive, 1);
+ test(msg, SPECIAL_SYSTEM_EXCLUSIVE, dataExclusive, 2);
+
+ ////////////////////////////
+ // SysexMessage.setMessage()
+ ////////////////////////////
+ msg = new SysexMessage();
+ msg.setMessage(dataExclusive, 1);
+ test(msg, SYSTEM_EXCLUSIVE, empty, 1);
+ msg = new SysexMessage();
+ msg.setMessage(dataSpecialExclusive, 1);
+ test(msg, SPECIAL_SYSTEM_EXCLUSIVE, empty, 1);
+ msg = new SysexMessage();
+ msg.setMessage(SYSTEM_EXCLUSIVE, empty, 0);
+ test(msg, SYSTEM_EXCLUSIVE, empty, 1);
+ msg = new SysexMessage();
+ msg.setMessage(SPECIAL_SYSTEM_EXCLUSIVE, empty, 0);
+ test(msg, SPECIAL_SYSTEM_EXCLUSIVE, empty, 1);
+ msg = new SysexMessage();
+ msg.setMessage(SYSTEM_EXCLUSIVE, dataSpecialExclusive, 1);
+ test(msg, SYSTEM_EXCLUSIVE, dataSpecialExclusive, 2);
+ msg = new SysexMessage();
+ msg.setMessage(SPECIAL_SYSTEM_EXCLUSIVE, dataExclusive, 1);
+ test(msg, SPECIAL_SYSTEM_EXCLUSIVE, dataExclusive, 2);
+ }
+
+ static void test(SysexMessage msg, int status, byte[] data, int length) {
+ if (msg.getStatus() != status) {
+ System.err.println("Expected status: " + status);
+ System.err.println("Actual status: " + msg.getStatus());
+ throw new RuntimeException();
+ }
+ if (msg.getLength() != length) {
+ System.err.println("Expected length: " + length);
+ System.err.println("Actual length: " + msg.getLength());
+ throw new RuntimeException();
+ }
+ if (!Arrays.equals(msg.getData(), data)) {
+ System.err.println("Expected data: " + Arrays.toString(data));
+ System.err.println("Actual data: " + Arrays.toString(msg.getData()));
+ throw new RuntimeException();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/sound/midi/SysexMessage/Exceptions.java Thu Apr 11 07:44:51 2019 -0400
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * 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 javax.sound.midi.InvalidMidiDataException;
+import javax.sound.midi.SysexMessage;
+
+import static javax.sound.midi.SysexMessage.SYSTEM_EXCLUSIVE;
+
+/**
+ * @test
+ * @bug 8221445
+ * @summary Checks exceptions thrown by javax.sound.midi.SysexMessage class
+ */
+public final class Exceptions {
+
+ public static void main(final String[] args) throws Exception {
+ testInvalidMidiDataException();
+ testIndexOutOfBoundsException();
+ testNullPointerException();
+ }
+
+ private static void testInvalidMidiDataException() {
+ try {
+ // data should conatins a status byte
+ new SysexMessage(new byte[0], 0);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final InvalidMidiDataException ignored) {
+ // ok
+ }
+ try {
+ // length is zero, no space for the status byte
+ new SysexMessage(new byte[]{(byte) (SYSTEM_EXCLUSIVE)}, 0);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final InvalidMidiDataException ignored) {
+ // ok
+ }
+ try {
+ // status should conatins a status byte (0xF0 or 0xF7)
+ new SysexMessage(0, new byte[0], 2);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final InvalidMidiDataException ignored) {
+ // ok
+ }
+ SysexMessage sysexMessage = new SysexMessage();
+ try {
+ // data should conatins a status byte
+ sysexMessage.setMessage(new byte[0], 0);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final InvalidMidiDataException ignored) {
+ // ok
+ }
+ try {
+ // length is zero, no space for the status byte
+ sysexMessage.setMessage(new byte[]{(byte) (SYSTEM_EXCLUSIVE)}, 0);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final InvalidMidiDataException ignored) {
+ // ok
+ }
+ try {
+ // data should conatins a status byte (0xF0 or 0xF7)
+ sysexMessage.setMessage(new byte[]{0}, 0);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final InvalidMidiDataException ignored) {
+ // ok
+ }
+ try {
+ // status should conatins a status byte (0xF0 or 0xF7)
+ sysexMessage.setMessage(0, new byte[0], 0);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final InvalidMidiDataException ignored) {
+ // ok
+ }
+ }
+
+ private static void testIndexOutOfBoundsException() throws Exception {
+ // length is bigger than data
+ try {
+ new SysexMessage(new byte[]{(byte) (0xF0 & 0xFF)}, 2);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final IndexOutOfBoundsException ignored) {
+ // ok
+ }
+ try {
+ new SysexMessage(0xF0, new byte[0], 2);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final IndexOutOfBoundsException ignored) {
+ // ok
+ }
+ SysexMessage sysexMessage = new SysexMessage();
+ try {
+ sysexMessage.setMessage(new byte[]{(byte) (0xF0 & 0xFF)}, 2);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final IndexOutOfBoundsException ignored) {
+ // ok
+ }
+ try {
+ sysexMessage.setMessage(0xF0, new byte[0], 2);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final IndexOutOfBoundsException ignored) {
+ // ok
+ }
+
+ // length is negative
+ try {
+ new SysexMessage(new byte[]{(byte) (0xF0 & 0xFF)}, -1);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final IndexOutOfBoundsException ignored) {
+ // ok
+ }
+ try {
+ new SysexMessage(0xF0, new byte[0], -1);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final IndexOutOfBoundsException ignored) {
+ // ok
+ }
+ sysexMessage = new SysexMessage();
+ try {
+ sysexMessage.setMessage(new byte[]{(byte) (0xF0 & 0xFF)}, -1);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final IndexOutOfBoundsException ignored) {
+ // ok
+ }
+ try {
+ sysexMessage.setMessage(0xF0, new byte[0], -1);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final IndexOutOfBoundsException ignored) {
+ // ok
+ }
+ }
+
+ private static void testNullPointerException() throws Exception {
+ try {
+ new SysexMessage(null, 0);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final NullPointerException ignored) {
+ // ok
+ }
+ try {
+ new SysexMessage(SYSTEM_EXCLUSIVE, null, 2);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final NullPointerException ignored) {
+ // ok
+ }
+ SysexMessage sysexMessage = new SysexMessage();
+ try {
+ sysexMessage.setMessage(null, 0);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final NullPointerException ignored) {
+ // ok
+ }
+ sysexMessage = new SysexMessage();
+ try {
+ sysexMessage.setMessage(SYSTEM_EXCLUSIVE, null, 2);
+ throw new RuntimeException("Expected exception is not thrown");
+ } catch (final NullPointerException ignored) {
+ // ok
+ }
+ }
+}
--- a/test/jdk/sun/security/util/misc/SetNullSigParams.java Tue Apr 09 16:11:54 2019 -0400
+++ b/test/jdk/sun/security/util/misc/SetNullSigParams.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* 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,8 +23,8 @@
/*
* @test
- * @bug 8214096
- * @summary Make sure SignatureUtil can accept null algorithm parameters
+ * @bug 8214096 8216039
+ * @summary Make sure SignatureUtil works with null algorithm parameters
* @modules java.base/sun.security.util
*/
import java.security.*;
@@ -35,8 +35,8 @@
public static void main(String[] args) throws Exception {
Signature sig = new SpecialSigImpl();
- SignatureUtil.specialSetParameter(sig, (byte[]) null);
- SignatureUtil.specialSetParameter(sig, (AlgorithmParameters) null);
+ SignatureUtil.initVerifyWithParam(sig, (PublicKey) null, null);
+ SignatureUtil.initSignWithParam(sig, null, null, null);
}
// Sample Signature impl class which simulates 3rd party provider behavior
--- a/test/langtools/jdk/javadoc/doclet/testHtmlLandmarkRegions/TestHtmlLandmarkRegions.java Tue Apr 09 16:11:54 2019 -0400
+++ b/test/langtools/jdk/javadoc/doclet/testHtmlLandmarkRegions/TestHtmlLandmarkRegions.java Thu Apr 11 07:44:51 2019 -0400
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8210047 8199892
+ * @bug 8210047 8199892 8215599
* @summary some pages contains content outside of landmark region
* @library /tools/lib ../../lib
* @modules
@@ -57,7 +57,6 @@
TestHtmlLandmarkRegions() {
tb = new ToolBox();
- setAutomaticCheckLinks(false); // @ignore 8217013
}
@Test
--- a/test/langtools/jdk/javadoc/doclet/testIndexWithModules/TestIndexWithModules.java Tue Apr 09 16:11:54 2019 -0400
+++ b/test/langtools/jdk/javadoc/doclet/testIndexWithModules/TestIndexWithModules.java Thu Apr 11 07:44:51 2019 -0400
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8190875
+ * @bug 8190875 8215599
* @summary modules not listed in overview/index page
* @library /tools/lib ../../lib
* @modules
@@ -83,7 +83,6 @@
//multiple modules with frames
@Test
public void testIndexWithMultipleModules1(Path base) throws Exception {
- setAutomaticCheckLinks(false); // @ignore 8217013
Path out = base.resolve("out");
javadoc("-d", out.toString(),
"--module-source-path", src.toString(),
@@ -98,7 +97,6 @@
"<a href=\"m1/module-summary.html\">m1</a>",
"<a href=\"m3/module-summary.html\">m3</a>",
"<a href=\"m4/module-summary.html\">m4</a>");
- setAutomaticCheckLinks(true); // @ignore 8217013
}
//multiple modules with out frames
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/T8222035/MinContextOpTest.java Thu Apr 11 07:44:51 2019 -0400
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, Google LLC. All rights reserved.
+ * 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 8222035
+ * @summary minimal inference context optimization is forcing resolution with incomplete constraints
+ * @compile/fail/ref=MinContextOpTest.out -XDrawDiagnostics MinContextOpTest.java
+ */
+
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collector;
+import java.util.stream.Stream;
+
+public class MinContextOpTest {
+ abstract class A {
+ abstract static class T<K> {
+ abstract String f();
+ }
+
+ abstract <E> Function<E, E> id();
+
+ abstract static class ImmutableMap<K, V> implements Map<K, V> {}
+
+ abstract <T, K, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableMap(
+ Function<? super T, ? extends K> k, Function<? super T, ? extends V> v);
+
+ ImmutableMap<String, T<?>> test(Stream<T> stream) {
+ return stream.collect(toImmutableMap(T::f, id()));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/T8222035/MinContextOpTest.out Thu Apr 11 07:44:51 2019 -0400
@@ -0,0 +1,4 @@
+MinContextOpTest.java:38:25: compiler.err.mod.not.allowed.here: static
+MinContextOpTest.java:44:25: compiler.err.mod.not.allowed.here: static
+MinContextOpTest.java:50:34: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: T,K,V,E, (compiler.misc.inconvertible.types: java.util.function.Function<MinContextOpTest.A.T,MinContextOpTest.A.T>, java.util.function.Function<? super MinContextOpTest.A.T,? extends MinContextOpTest.A.T<?>>))
+3 errors
--- a/test/lib/sun/hotspot/WhiteBox.java Tue Apr 09 16:11:54 2019 -0400
+++ b/test/lib/sun/hotspot/WhiteBox.java Thu Apr 11 07:44:51 2019 -0400
@@ -541,7 +541,7 @@
public native void disableElfSectionCache();
// Resolved Method Table
- public native int resolvedMethodRemovedCount();
+ public native long resolvedMethodItemsCount();
// Protection Domain Table
public native int protectionDomainRemovedCount();
--- a/test/lib/sun/hotspot/gc/GC.java Tue Apr 09 16:11:54 2019 -0400
+++ b/test/lib/sun/hotspot/gc/GC.java Thu Apr 11 07:44:51 2019 -0400
@@ -70,4 +70,16 @@
public static boolean isSelectedErgonomically() {
return WB.isGCSelectedErgonomically();
}
+
+ /**
+ * @return the selected GC.
+ */
+ public static GC selected() {
+ for (GC gc : values()) {
+ if (gc.isSelected()) {
+ return gc;
+ }
+ }
+ throw new IllegalStateException("No selected GC found");
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/micro/org/openjdk/bench/java/lang/MathBench.java Thu Apr 11 07:44:51 2019 -0400
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
+ * 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.openjdk.bench.java.lang;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.CompilerControl;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Threads;
+
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@State(Scope.Thread)
+public class MathBench {
+
+ @Param("0")
+ public long seed;
+
+ public int dividend;
+ public int divisor;
+
+ public long longDividend;
+ public long longDivisor;
+
+ @Setup
+ public void setupValues() {
+ Random random = new Random(seed);
+ dividend = Math.abs(random.nextInt() + 4711);
+ divisor = Math.abs(random.nextInt(dividend) + 17);
+ longDividend = Math.abs(random.nextLong() + 4711L);
+ longDivisor = Math.abs(random.nextLong() + longDividend);
+ }
+
+ @Benchmark
+ @CompilerControl(CompilerControl.Mode.DONT_INLINE)
+ public int floorModIntIntPositive() {
+ return Math.floorMod(dividend, divisor);
+ }
+
+ @Benchmark
+ @CompilerControl(CompilerControl.Mode.DONT_INLINE)
+ public int floorModIntInt() {
+ return Math.floorMod( dividend, divisor) +
+ Math.floorMod( dividend, -divisor) +
+ Math.floorMod(-dividend, divisor) +
+ Math.floorMod(-dividend, -divisor);
+ }
+
+ @Benchmark
+ @CompilerControl(CompilerControl.Mode.DONT_INLINE)
+ public int floorModLongInt() {
+ return Math.floorMod( longDividend, divisor) +
+ Math.floorMod( longDividend, -divisor) +
+ Math.floorMod(-longDividend, divisor) +
+ Math.floorMod(-longDividend, -divisor);
+ }
+
+ @Benchmark
+ @CompilerControl(CompilerControl.Mode.DONT_INLINE)
+ public long floorModLongLong() {
+ return Math.floorMod( longDividend, longDivisor) +
+ Math.floorMod( longDividend, -longDivisor) +
+ Math.floorMod(-longDividend, longDivisor) +
+ Math.floorMod(-longDividend, -longDivisor);
+ }
+
+}
--- a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java Tue Apr 09 16:11:54 2019 -0400
+++ b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java Thu Apr 11 07:44:51 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* 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,6 +42,8 @@
private String[] str16p8p7;
private String[] str3p9p8;
private String[] str22p40p31;
+ private StringBuilder sbLatin1;
+ private StringBuilder sbUtf16;
@Setup
public void setup() {
@@ -53,6 +55,8 @@
str16p8p7 = new String[]{"1234567890123456", "12345678", "1234567"};
str3p9p8 = new String[]{"123", "123456789", "12345678"};
str22p40p31 = new String[]{"1234567890123456789012", "1234567890123456789012345678901234567890", "1234567890123456789012345678901"};
+ sbLatin1 = new StringBuilder("Latin1 string");
+ sbUtf16 = new StringBuilder("UTF-\uFF11\uFF16 string");
}
/** StringBuilder wins over StringMaker. */
@@ -256,4 +260,24 @@
result.append("stringelinglinglinglong");
return result.toString();
}
+
+ @Benchmark
+ public StringBuilder fromLatin1String() {
+ return new StringBuilder("Latin1 string");
+ }
+
+ @Benchmark
+ public StringBuilder fromUtf16String() {
+ return new StringBuilder("UTF-\uFF11\uFF16 string");
+ }
+
+ @Benchmark
+ public StringBuilder fromLatin1StringBuilder() {
+ return new StringBuilder(sbLatin1);
+ }
+
+ @Benchmark
+ public StringBuilder fromUtf16StringBuilder() {
+ return new StringBuilder(sbUtf16);
+ }
}