--- a/make/autoconf/lib-bundled.m4 Tue May 14 11:23:08 2019 +0530
+++ b/make/autoconf/lib-bundled.m4 Wed May 15 13:54:43 2019 +0530
@@ -161,8 +161,8 @@
AC_MSG_CHECKING([for which zlib to use])
DEFAULT_ZLIB=system
- if test "x$OPENJDK_TARGET_OS" = xwindows; then
- # On windows default is bundled...on others default is system
+ if test "x$OPENJDK_TARGET_OS" = xwindows -o "x$OPENJDK_TARGET_OS" = xaix; then
+ # On windows and aix default is bundled, on others default is system
DEFAULT_ZLIB=bundled
fi
--- a/make/hotspot/gensrc/GensrcJvmti.gmk Tue May 14 11:23:08 2019 +0530
+++ b/make/hotspot/gensrc/GensrcJvmti.gmk Wed May 15 13:54:43 2019 +0530
@@ -100,12 +100,17 @@
endef
$(eval $(call SetupJvmtiGeneration, jvmtiEnter.cpp, jvmtiEnter.xsl, \
+ -PARAM majorversion $(VERSION_FEATURE) \
-PARAM interface jvmti))
$(eval $(call SetupJvmtiGeneration, jvmtiEnterTrace.cpp, jvmtiEnter.xsl, \
+ -PARAM majorversion $(VERSION_FEATURE) \
-PARAM interface jvmti -PARAM trace Trace))
-$(eval $(call SetupJvmtiGeneration, jvmtiEnv.hpp, jvmtiHpp.xsl))
-$(eval $(call SetupJvmtiGeneration, jvmti.h, jvmtiH.xsl))
-$(eval $(call SetupJvmtiGeneration, jvmti.html, jvmti.xsl))
+$(eval $(call SetupJvmtiGeneration, jvmtiEnv.hpp, jvmtiHpp.xsl, \
+ -PARAM majorversion $(VERSION_FEATURE)))
+$(eval $(call SetupJvmtiGeneration, jvmti.h, jvmtiH.xsl, \
+ -PARAM majorversion $(VERSION_FEATURE)))
+$(eval $(call SetupJvmtiGeneration, jvmti.html, jvmti.xsl, \
+ -PARAM majorversion $(VERSION_FEATURE)))
JVMTI_BC_SRCDIR := $(TOPDIR)/src/hotspot/share/interpreter
--- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp Wed May 15 13:54:43 2019 +0530
@@ -1413,7 +1413,6 @@
out_sig_bt[argc++] = in_sig_bt[i];
}
} else {
- Thread* THREAD = Thread::current();
in_elem_bt = NEW_RESOURCE_ARRAY(BasicType, total_in_args);
SignatureStream ss(method->signature());
for (int i = 0; i < total_in_args ; i++ ) {
@@ -1421,7 +1420,7 @@
// Arrays are passed as int, elem* pair
out_sig_bt[argc++] = T_INT;
out_sig_bt[argc++] = T_ADDRESS;
- Symbol* atype = ss.as_symbol(CHECK_NULL);
+ Symbol* atype = ss.as_symbol();
const char* at = atype->as_C_string();
if (strlen(at) == 2) {
assert(at[0] == '[', "must be");
--- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Wed May 15 13:54:43 2019 +0530
@@ -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.
* Copyright (c) 2012, 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -1908,14 +1908,13 @@
out_sig_bt[argc++] = in_sig_bt[i];
}
} else {
- Thread* THREAD = Thread::current();
in_elem_bt = NEW_RESOURCE_ARRAY(BasicType, total_c_args);
SignatureStream ss(method->signature());
int o = 0;
for (int i = 0; i < total_in_args ; i++, o++) {
if (in_sig_bt[i] == T_ARRAY) {
// Arrays are passed as int, elem* pair
- Symbol* atype = ss.as_symbol(CHECK_NULL);
+ Symbol* atype = ss.as_symbol();
const char* at = atype->as_C_string();
if (strlen(at) == 2) {
assert(at[0] == '[', "must be");
--- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -1618,14 +1618,13 @@
out_sig_bt[argc++] = in_sig_bt[i];
}
} else {
- Thread* THREAD = Thread::current();
in_elem_bt = NEW_RESOURCE_ARRAY(BasicType, total_in_args);
SignatureStream ss(method->signature());
int o = 0;
for (int i = 0; i < total_in_args; i++, o++) {
if (in_sig_bt[i] == T_ARRAY) {
// Arrays are passed as tuples (int, elem*).
- Symbol* atype = ss.as_symbol(CHECK_NULL);
+ Symbol* atype = ss.as_symbol();
const char* at = atype->as_C_string();
if (strlen(at) == 2) {
assert(at[0] == '[', "must be");
--- a/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -1906,7 +1906,7 @@
// Arrays are passed as int, elem* pair
out_sig_bt[argc++] = T_INT;
out_sig_bt[argc++] = T_ADDRESS;
- Symbol* atype = ss.as_symbol(CHECK_NULL);
+ Symbol* atype = ss.as_symbol();
const char* at = atype->as_C_string();
if (strlen(at) == 2) {
assert(at[0] == '[', "must be");
--- a/src/hotspot/cpu/x86/compiledIC_x86.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/cpu/x86/compiledIC_x86.cpp Wed May 15 13:54:43 2019 +0530
@@ -159,10 +159,10 @@
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
#ifdef ASSERT
- // read the value once
- volatile intptr_t data = method_holder->data();
- volatile address destination = jump->jump_destination();
- assert(data == 0 || data == (intptr_t)callee(),
+ Method* old_method = reinterpret_cast<Method*>(method_holder->data());
+ address destination = jump->jump_destination();
+ assert(old_method == NULL || old_method == callee() ||
+ !old_method->method_holder()->is_loader_alive(),
"a) MT-unsafe modification of inline cache");
assert(destination == (address)-1 || destination == entry,
"b) MT-unsafe modification of inline cache");
--- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp Wed May 15 13:54:43 2019 +0530
@@ -30,6 +30,7 @@
#include "interpreter/interp_masm.hpp"
#include "memory/universe.hpp"
#include "runtime/jniHandles.hpp"
+#include "runtime/sharedRuntime.hpp"
#include "runtime/thread.hpp"
#define __ masm->
@@ -344,3 +345,33 @@
__ bind(continuation);
#endif
}
+
+void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) {
+ BarrierSetNMethod* bs = BarrierSet::barrier_set()->barrier_set_nmethod();
+ if (bs == NULL) {
+ return;
+ }
+
+ Label bad_call;
+ __ cmpptr(rbx, 0); // rbx contains the incoming method for c2i adapters.
+ __ jcc(Assembler::equal, bad_call);
+
+ // Pointer chase to the method holder to find out if the method is concurrently unloading.
+ Label method_live;
+ __ load_method_holder_cld(rscratch1, rbx);
+
+ // Is it a strong CLD?
+ __ movl(rscratch2, Address(rscratch1, ClassLoaderData::keep_alive_offset()));
+ __ cmpptr(rscratch2, 0);
+ __ jcc(Assembler::greater, method_live);
+
+ // Is it a weak but alive CLD?
+ __ movptr(rscratch1, Address(rscratch1, ClassLoaderData::holder_offset()));
+ __ resolve_weak_handle(rscratch1, rscratch2);
+ __ cmpptr(rscratch1, 0);
+ __ jcc(Assembler::notEqual, method_live);
+
+ __ bind(bad_call);
+ __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub()));
+ __ bind(method_live);
+}
--- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp Wed May 15 13:54:43 2019 +0530
@@ -85,6 +85,7 @@
virtual void barrier_stubs_init() {}
virtual void nmethod_entry_barrier(MacroAssembler* masm);
+ virtual void c2i_entry_barrier(MacroAssembler* masm);
};
#endif // CPU_X86_GC_SHARED_BARRIERSETASSEMBLER_X86_HPP
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp Wed May 15 13:54:43 2019 +0530
@@ -5175,6 +5175,23 @@
result, Address(result, 0), tmp, /*tmp_thread*/noreg);
}
+// ((WeakHandle)result).resolve();
+void MacroAssembler::resolve_weak_handle(Register rresult, Register rtmp) {
+ assert_different_registers(rresult, rtmp);
+ Label resolved;
+
+ // A null weak handle resolves to null.
+ cmpptr(rresult, 0);
+ jcc(Assembler::equal, resolved);
+
+ // Only 64 bit platforms support GCs that require a tmp register
+ // Only IN_HEAP loads require a thread_tmp register
+ // WeakHandle::resolve is an indirection like jweak.
+ access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF,
+ rresult, Address(rresult, 0), rtmp, /*tmp_thread*/noreg);
+ bind(resolved);
+}
+
void MacroAssembler::load_mirror(Register mirror, Register method, Register tmp) {
// get mirror
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
@@ -5185,6 +5202,13 @@
resolve_oop_handle(mirror, tmp);
}
+void MacroAssembler::load_method_holder_cld(Register rresult, Register rmethod) {
+ movptr(rresult, Address(rmethod, Method::const_offset()));
+ movptr(rresult, Address(rresult, ConstMethod::constants_offset()));
+ movptr(rresult, Address(rresult, ConstantPool::pool_holder_offset_in_bytes()));
+ movptr(rresult, Address(rresult, InstanceKlass::class_loader_data_offset()));
+}
+
void MacroAssembler::load_klass(Register dst, Register src) {
#ifdef _LP64
if (UseCompressedClassPointers) {
--- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp Wed May 15 13:54:43 2019 +0530
@@ -313,7 +313,9 @@
void testbool(Register dst);
void resolve_oop_handle(Register result, Register tmp = rscratch2);
+ void resolve_weak_handle(Register result, Register tmp);
void load_mirror(Register mirror, Register method, Register tmp = rscratch2);
+ void load_method_holder_cld(Register rresult, Register rmethod);
// oop manipulations
void load_klass(Register dst, Register src);
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -1593,7 +1593,6 @@
out_sig_bt[argc++] = in_sig_bt[i];
}
} else {
- Thread* THREAD = Thread::current();
in_elem_bt = NEW_RESOURCE_ARRAY(BasicType, total_in_args);
SignatureStream ss(method->signature());
for (int i = 0; i < total_in_args ; i++ ) {
@@ -1601,7 +1600,7 @@
// Arrays are passed as int, elem* pair
out_sig_bt[argc++] = T_INT;
out_sig_bt[argc++] = T_ADDRESS;
- Symbol* atype = ss.as_symbol(CHECK_NULL);
+ Symbol* atype = ss.as_symbol();
const char* at = atype->as_C_string();
if (strlen(at) == 2) {
assert(at[0] == '[', "must be");
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -971,6 +971,9 @@
address c2i_entry = __ pc();
+ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->c2i_entry_barrier(masm);
+
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
__ flush();
@@ -1968,7 +1971,6 @@
out_sig_bt[argc++] = in_sig_bt[i];
}
} else {
- Thread* THREAD = Thread::current();
in_elem_bt = NEW_RESOURCE_ARRAY(BasicType, total_in_args);
SignatureStream ss(method->signature());
for (int i = 0; i < total_in_args ; i++ ) {
@@ -1976,7 +1978,7 @@
// Arrays are passed as int, elem* pair
out_sig_bt[argc++] = T_INT;
out_sig_bt[argc++] = T_ADDRESS;
- Symbol* atype = ss.as_symbol(CHECK_NULL);
+ Symbol* atype = ss.as_symbol();
const char* at = atype->as_C_string();
if (strlen(at) == 2) {
assert(at[0] == '[', "must be");
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp Wed May 15 13:54:43 2019 +0530
@@ -32,6 +32,7 @@
#include "runtime/java.hpp"
#include "runtime/os.hpp"
#include "runtime/stubCodeGenerator.hpp"
+#include "utilities/virtualizationSupport.hpp"
#include "vm_version_x86.hpp"
@@ -1581,6 +1582,7 @@
st->print_cr("KVM virtualization detected");
} else if (vrt == VMWare) {
st->print_cr("VMWare virtualization detected");
+ VirtualizationSupport::print_virtualization_info(st);
} else if (vrt == HyperV) {
st->print_cr("HyperV virtualization detected");
}
@@ -1684,6 +1686,8 @@
if (strncmp("VMwareVMware", signature, 12) == 0) {
Abstract_VM_Version::_detected_virtualization = VMWare;
+ // check for extended metrics from guestlib
+ VirtualizationSupport::initialize();
}
if (strncmp("Microsoft Hv", signature, 12) == 0) {
--- a/src/hotspot/os/aix/os_aix.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/os/aix/os_aix.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2018 SAP SE. All rights reserved.
+ * Copyright (c) 2012, 2019 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1389,12 +1389,15 @@
os::Posix::print_rlimit_info(st);
+ // _SC_THREAD_THREADS_MAX is the maximum number of threads within a process.
+ long tmax = sysconf(_SC_THREAD_THREADS_MAX);
+ st->print_cr("maximum #threads within a process:%ld", tmax);
+
// load average
st->print("load average:");
double loadavg[3] = {-1.L, -1.L, -1.L};
os::loadavg(loadavg, 3);
- st->print("%0.02f %0.02f %0.02f", loadavg[0], loadavg[1], loadavg[2]);
- st->cr();
+ st->print_cr("%0.02f %0.02f %0.02f", loadavg[0], loadavg[1], loadavg[2]);
// print wpar info
libperfstat::wparinfo_t wi;
--- a/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -39,7 +39,7 @@
#endif
static int z_get_mempolicy(uint32_t* mode, const unsigned long *nmask, unsigned long maxnode, uintptr_t addr, int flags) {
- return syscall(__NR_get_mempolicy, mode, nmask, maxnode, addr, flags);
+ return syscall(SYS_get_mempolicy, mode, nmask, maxnode, addr, flags);
}
void ZNUMA::initialize_platform() {
--- a/src/hotspot/os/windows/os_windows.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/os/windows/os_windows.cpp Wed May 15 13:54:43 2019 +0530
@@ -201,7 +201,7 @@
char *home_path;
char *dll_path;
char *pslash;
- char *bin = "\\bin";
+ const char *bin = "\\bin";
char home_dir[MAX_PATH + 1];
char *alt_home_dir = ::getenv("_ALT_JAVA_HOME_DIR");
@@ -2185,7 +2185,7 @@
#define def_excpt(val) { #val, (val) }
-static const struct { char* name; uint number; } exceptlabels[] = {
+static const struct { const char* name; uint number; } exceptlabels[] = {
def_excpt(EXCEPTION_ACCESS_VIOLATION),
def_excpt(EXCEPTION_DATATYPE_MISALIGNMENT),
def_excpt(EXCEPTION_BREAKPOINT),
@@ -5335,7 +5335,7 @@
DWORD exit_code;
char * cmd_string;
- char * cmd_prefix = "cmd /C ";
+ const char * cmd_prefix = "cmd /C ";
size_t len = strlen(cmd) + strlen(cmd_prefix) + 1;
cmd_string = NEW_C_HEAP_ARRAY_RETURN_NULL(char, len, mtInternal);
if (cmd_string == NULL) {
@@ -5674,8 +5674,8 @@
*/
int os::get_signal_number(const char* name) {
static const struct {
- char* name;
- int number;
+ const char* name;
+ int number;
} siglabels [] =
// derived from version 6.0 VC98/include/signal.h
{"ABRT", SIGABRT, // abnormal termination triggered by abort cl
--- a/src/hotspot/os_cpu/linux_x86/gc/z/zBackingFile_linux_x86.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/os_cpu/linux_x86/gc/z/zBackingFile_linux_x86.cpp Wed May 15 13:54:43 2019 +0530
@@ -26,8 +26,10 @@
#include "gc/z/zBackingFile_linux_x86.hpp"
#include "gc/z/zBackingPath_linux_x86.hpp"
#include "gc/z/zErrno.hpp"
+#include "gc/z/zGlobals.hpp"
#include "gc/z/zLargePages.inline.hpp"
#include "logging/log.hpp"
+#include "runtime/init.hpp"
#include "runtime/os.hpp"
#include "utilities/align.hpp"
#include "utilities/debug.hpp"
@@ -36,9 +38,54 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/statfs.h>
+#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
+//
+// Support for building on older Linux systems
+//
+
+// System calls
+#ifndef SYS_fallocate
+#define SYS_fallocate 285
+#endif
+#ifndef SYS_memfd_create
+#define SYS_memfd_create 319
+#endif
+
+// memfd_create(2) flags
+#ifndef MFD_CLOEXEC
+#define MFD_CLOEXEC 0x0001U
+#endif
+#ifndef MFD_HUGETLB
+#define MFD_HUGETLB 0x0004U
+#endif
+
+// open(2) flags
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 02000000
+#endif
+#ifndef O_TMPFILE
+#define O_TMPFILE (020000000 | O_DIRECTORY)
+#endif
+
+// fallocate(2) flags
+#ifndef FALLOC_FL_KEEP_SIZE
+#define FALLOC_FL_KEEP_SIZE 0x01
+#endif
+#ifndef FALLOC_FL_PUNCH_HOLE
+#define FALLOC_FL_PUNCH_HOLE 0x02
+#endif
+
+// Filesystem types, see statfs(2)
+#ifndef TMPFS_MAGIC
+#define TMPFS_MAGIC 0x01021994
+#endif
+#ifndef HUGETLBFS_MAGIC
+#define HUGETLBFS_MAGIC 0x958458f6
+#endif
+
// Filesystem names
#define ZFILESYSTEM_TMPFS "tmpfs"
#define ZFILESYSTEM_HUGETLBFS "hugetlbfs"
@@ -49,31 +96,6 @@
// Java heap filename
#define ZFILENAME_HEAP "java_heap"
-// Support for building on older Linux systems
-#ifndef __NR_memfd_create
-#define __NR_memfd_create 319
-#endif
-#ifndef MFD_CLOEXEC
-#define MFD_CLOEXEC 0x0001U
-#endif
-#ifndef MFD_HUGETLB
-#define MFD_HUGETLB 0x0004U
-#endif
-#ifndef O_CLOEXEC
-#define O_CLOEXEC 02000000
-#endif
-#ifndef O_TMPFILE
-#define O_TMPFILE (020000000 | O_DIRECTORY)
-#endif
-
-// Filesystem types, see statfs(2)
-#ifndef TMPFS_MAGIC
-#define TMPFS_MAGIC 0x01021994
-#endif
-#ifndef HUGETLBFS_MAGIC
-#define HUGETLBFS_MAGIC 0x958458f6
-#endif
-
// Preferred tmpfs mount points, ordered by priority
static const char* z_preferred_tmpfs_mountpoints[] = {
"/dev/shm",
@@ -88,15 +110,22 @@
NULL
};
-static int z_memfd_create(const char *name, unsigned int flags) {
- return syscall(__NR_memfd_create, name, flags);
+static int z_fallocate_hugetlbfs_attempts = 3;
+static bool z_fallocate_supported = true;
+
+static int z_fallocate(int fd, int mode, size_t offset, size_t length) {
+ return syscall(SYS_fallocate, fd, mode, offset, length);
}
-bool ZBackingFile::_hugetlbfs_mmap_retry = true;
+static int z_memfd_create(const char *name, unsigned int flags) {
+ return syscall(SYS_memfd_create, name, flags);
+}
ZBackingFile::ZBackingFile() :
_fd(-1),
+ _size(0),
_filesystem(0),
+ _block_size(0),
_available(0),
_initialized(false) {
@@ -107,46 +136,53 @@
}
// Get filesystem statistics
- struct statfs statfs_buf;
- if (fstatfs(_fd, &statfs_buf) == -1) {
+ struct statfs buf;
+ if (fstatfs(_fd, &buf) == -1) {
ZErrno err;
- log_error(gc, init)("Failed to determine filesystem type for backing file (%s)",
- err.to_string());
+ log_error(gc)("Failed to determine filesystem type for backing file (%s)", err.to_string());
return;
}
- _filesystem = statfs_buf.f_type;
- _available = statfs_buf.f_bavail * statfs_buf.f_bsize;
+ _filesystem = buf.f_type;
+ _block_size = buf.f_bsize;
+ _available = buf.f_bavail * _block_size;
// Make sure we're on a supported filesystem
if (!is_tmpfs() && !is_hugetlbfs()) {
- log_error(gc, init)("Backing file must be located on a %s or a %s filesystem",
- ZFILESYSTEM_TMPFS, ZFILESYSTEM_HUGETLBFS);
+ log_error(gc)("Backing file must be located on a %s or a %s filesystem",
+ ZFILESYSTEM_TMPFS, ZFILESYSTEM_HUGETLBFS);
return;
}
// Make sure the filesystem type matches requested large page type
if (ZLargePages::is_transparent() && !is_tmpfs()) {
- log_error(gc, init)("-XX:+UseTransparentHugePages can only be enable when using a %s filesystem",
- ZFILESYSTEM_TMPFS);
+ log_error(gc)("-XX:+UseTransparentHugePages can only be enable when using a %s filesystem",
+ ZFILESYSTEM_TMPFS);
return;
}
if (ZLargePages::is_transparent() && !tmpfs_supports_transparent_huge_pages()) {
- log_error(gc, init)("-XX:+UseTransparentHugePages on a %s filesystem not supported by kernel",
- ZFILESYSTEM_TMPFS);
+ log_error(gc)("-XX:+UseTransparentHugePages on a %s filesystem not supported by kernel",
+ ZFILESYSTEM_TMPFS);
return;
}
if (ZLargePages::is_explicit() && !is_hugetlbfs()) {
- log_error(gc, init)("-XX:+UseLargePages (without -XX:+UseTransparentHugePages) can only be enabled when using a %s filesystem",
- ZFILESYSTEM_HUGETLBFS);
+ log_error(gc)("-XX:+UseLargePages (without -XX:+UseTransparentHugePages) can only be enabled "
+ "when using a %s filesystem", ZFILESYSTEM_HUGETLBFS);
return;
}
if (!ZLargePages::is_explicit() && is_hugetlbfs()) {
- log_error(gc, init)("-XX:+UseLargePages must be enabled when using a %s filesystem",
- ZFILESYSTEM_HUGETLBFS);
+ log_error(gc)("-XX:+UseLargePages must be enabled when using a %s filesystem",
+ ZFILESYSTEM_HUGETLBFS);
+ return;
+ }
+
+ const size_t expected_block_size = is_tmpfs() ? os::vm_page_size() : os::large_page_size();
+ if (expected_block_size != _block_size) {
+ log_error(gc)("%s filesystem has unexpected block size " SIZE_FORMAT " (expected " SIZE_FORMAT ")",
+ is_tmpfs() ? ZFILESYSTEM_TMPFS : ZFILESYSTEM_HUGETLBFS, _block_size, expected_block_size);
return;
}
@@ -165,7 +201,7 @@
if (fd == -1) {
ZErrno err;
log_debug(gc, init)("Failed to create memfd file (%s)",
- ((UseLargePages && err == EINVAL) ? "Hugepages not supported" : err.to_string()));
+ ((ZLargePages::is_explicit() && err == EINVAL) ? "Hugepages not supported" : err.to_string()));
return -1;
}
@@ -185,7 +221,7 @@
// Find mountpoint
ZBackingPath path(filesystem, preferred_mountpoints);
if (path.get() == NULL) {
- log_error(gc, init)("Use -XX:ZPath to specify the path to a %s filesystem", filesystem);
+ log_error(gc)("Use -XX:ZPath to specify the path to a %s filesystem", filesystem);
return -1;
}
@@ -201,7 +237,7 @@
struct stat stat_buf;
if (fstat(fd_anon, &stat_buf) == -1) {
ZErrno err;
- log_error(gc, init)("Failed to determine inode number for anonymous file (%s)", err.to_string());
+ log_error(gc)("Failed to determine inode number for anonymous file (%s)", err.to_string());
return -1;
}
@@ -220,14 +256,14 @@
const int fd = os::open(filename, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR);
if (fd == -1) {
ZErrno err;
- log_error(gc, init)("Failed to create file %s (%s)", filename, err.to_string());
+ log_error(gc)("Failed to create file %s (%s)", filename, err.to_string());
return -1;
}
// Unlink file
if (unlink(filename) == -1) {
ZErrno err;
- log_error(gc, init)("Failed to unlink file %s (%s)", filename, err.to_string());
+ log_error(gc)("Failed to unlink file %s (%s)", filename, err.to_string());
return -1;
}
@@ -262,6 +298,10 @@
return _fd;
}
+size_t ZBackingFile::size() const {
+ return _size;
+}
+
size_t ZBackingFile::available() const {
return _available;
}
@@ -280,147 +320,271 @@
return access(ZFILENAME_SHMEM_ENABLED, R_OK) == 0;
}
-bool ZBackingFile::try_split_and_expand_tmpfs(size_t offset, size_t length, size_t alignment) const {
- // Try first smaller part.
- const size_t offset0 = offset;
- const size_t length0 = align_up(length / 2, alignment);
- if (!try_expand_tmpfs(offset0, length0, alignment)) {
- return false;
+ZErrno ZBackingFile::fallocate_compat_ftruncate(size_t size) const {
+ while (ftruncate(_fd, size) == -1) {
+ if (errno != EINTR) {
+ // Failed
+ return errno;
+ }
}
- // Try second smaller part.
- const size_t offset1 = offset0 + length0;
- const size_t length1 = length - length0;
- if (!try_expand_tmpfs(offset1, length1, alignment)) {
- return false;
- }
-
- return true;
+ // Success
+ return 0;
}
-bool ZBackingFile::try_expand_tmpfs(size_t offset, size_t length, size_t alignment) const {
- assert(length > 0, "Invalid length");
- assert(is_aligned(length, alignment), "Invalid length");
-
- ZErrno err = posix_fallocate(_fd, offset, length);
-
- if (err == EINTR && length > alignment) {
- // Calling posix_fallocate() with a large length can take a long
- // time to complete. When running profilers, such as VTune, this
- // syscall will be constantly interrupted by signals. Expanding
- // the file in smaller steps avoids this problem.
- return try_split_and_expand_tmpfs(offset, length, alignment);
+ZErrno ZBackingFile::fallocate_compat_mmap(size_t offset, size_t length, bool touch) const {
+ // On hugetlbfs, mapping a file segment will fail immediately, without
+ // the need to touch the mapped pages first, if there aren't enough huge
+ // pages available to back the mapping.
+ void* const addr = mmap(0, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, offset);
+ if (addr == MAP_FAILED) {
+ // Failed
+ return errno;
}
- if (err) {
- log_error(gc)("Failed to allocate backing file (%s)", err.to_string());
- return false;
+ // Once mapped, the huge pages are only reserved. We need to touch them
+ // to associate them with the file segment. Note that we can not punch
+ // hole in file segments which only have reserved pages.
+ if (touch) {
+ char* const start = (char*)addr;
+ char* const end = start + length;
+ os::pretouch_memory(start, end, _block_size);
+ }
+
+ // Unmap again. From now on, the huge pages that were mapped are allocated
+ // to this file. There's no risk in getting SIGBUS when touching them.
+ if (munmap(addr, length) == -1) {
+ // Failed
+ return errno;
}
- return true;
-}
-
-bool ZBackingFile::try_expand_tmpfs(size_t offset, size_t length) const {
- assert(is_tmpfs(), "Wrong filesystem");
- return try_expand_tmpfs(offset, length, os::vm_page_size());
+ // Success
+ return 0;
}
-bool ZBackingFile::try_expand_hugetlbfs(size_t offset, size_t length) const {
- assert(is_hugetlbfs(), "Wrong filesystem");
+ZErrno ZBackingFile::fallocate_compat_pwrite(size_t offset, size_t length) const {
+ uint8_t data = 0;
+
+ // Allocate backing memory by writing to each block
+ for (size_t pos = offset; pos < offset + length; pos += _block_size) {
+ if (pwrite(_fd, &data, sizeof(data), pos) == -1) {
+ // Failed
+ return errno;
+ }
+ }
- // Prior to kernel 4.3, hugetlbfs did not support posix_fallocate().
- // Instead of posix_fallocate() we can use a well-known workaround,
- // which involves truncating the file to requested size and then try
- // to map it to verify that there are enough huge pages available to
- // back it.
- while (ftruncate(_fd, offset + length) == -1) {
- ZErrno err;
- if (err != EINTR) {
- log_error(gc)("Failed to truncate backing file (%s)", err.to_string());
- return false;
+ // Success
+ return 0;
+}
+
+ZErrno ZBackingFile::fallocate_fill_hole_compat(size_t offset, size_t length) {
+ // fallocate(2) is only supported by tmpfs since Linux 3.5, and by hugetlbfs
+ // since Linux 4.3. When fallocate(2) is not supported we emulate it using
+ // ftruncate/pwrite (for tmpfs) or ftruncate/mmap/munmap (for hugetlbfs).
+
+ const size_t end = offset + length;
+ if (end > _size) {
+ // Increase file size
+ const ZErrno err = fallocate_compat_ftruncate(end);
+ if (err) {
+ // Failed
+ return err;
}
}
- // If we fail mapping during initialization, i.e. when we are pre-mapping
- // the heap, then we wait and retry a few times before giving up. Otherwise
- // there is a risk that running JVMs back-to-back will fail, since there
- // is a delay between process termination and the huge pages owned by that
- // process being returned to the huge page pool and made available for new
- // allocations.
- void* addr = MAP_FAILED;
- const int max_attempts = 5;
- for (int attempt = 1; attempt <= max_attempts; attempt++) {
- addr = mmap(0, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, offset);
- if (addr != MAP_FAILED || !_hugetlbfs_mmap_retry) {
- // Mapping was successful or mmap retry is disabled
- break;
+ // Allocate backing memory
+ const ZErrno err = is_hugetlbfs() ? fallocate_compat_mmap(offset, length, false /* touch */)
+ : fallocate_compat_pwrite(offset, length);
+ if (err) {
+ if (end > _size) {
+ // Restore file size
+ fallocate_compat_ftruncate(_size);
}
- ZErrno err;
- log_debug(gc)("Failed to map backing file (%s), attempt %d of %d",
- err.to_string(), attempt, max_attempts);
+ // Failed
+ return err;
+ }
+
+ if (end > _size) {
+ // Record new file size
+ _size = end;
+ }
+
+ // Success
+ return 0;
+}
+
+ZErrno ZBackingFile::fallocate_fill_hole_syscall(size_t offset, size_t length) {
+ const int mode = 0; // Allocate
+ const int res = z_fallocate(_fd, mode, offset, length);
+ if (res == -1) {
+ // Failed
+ return errno;
+ }
+
+ const size_t end = offset + length;
+ if (end > _size) {
+ // Record new file size
+ _size = end;
+ }
+
+ // Success
+ return 0;
+}
- // Wait and retry in one second, in the hope that
- // huge pages will be available by then.
- sleep(1);
+ZErrno ZBackingFile::fallocate_fill_hole(size_t offset, size_t length) {
+ // Using compat mode is more efficient when allocating space on hugetlbfs.
+ // Note that allocating huge pages this way will only reserve them, and not
+ // associate them with segments of the file. We must guarantee that we at
+ // some point touch these segments, otherwise we can not punch hole in them.
+ if (z_fallocate_supported && !is_hugetlbfs()) {
+ const ZErrno err = fallocate_fill_hole_syscall(offset, length);
+ if (!err) {
+ // Success
+ return 0;
+ }
+
+ if (err != ENOSYS && err != EOPNOTSUPP) {
+ // Failed
+ return err;
+ }
+
+ // Not supported
+ log_debug(gc)("Falling back to fallocate() compatibility mode");
+ z_fallocate_supported = false;
+ }
+
+ return fallocate_fill_hole_compat(offset, length);
+}
+
+ZErrno ZBackingFile::fallocate_punch_hole(size_t offset, size_t length) {
+ if (is_hugetlbfs()) {
+ // We can only punch hole in pages that have been touched. Non-touched
+ // pages are only reserved, and not associated with any specific file
+ // segment. We don't know which pages have been previously touched, so
+ // we always touch them here to guarantee that we can punch hole.
+ const ZErrno err = fallocate_compat_mmap(offset, length, true /* touch */);
+ if (err) {
+ // Failed
+ return err;
+ }
}
- // Disable mmap retry from now on
- if (_hugetlbfs_mmap_retry) {
- _hugetlbfs_mmap_retry = false;
+ const int mode = FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE;
+ if (z_fallocate(_fd, mode, offset, length) == -1) {
+ // Failed
+ return errno;
+ }
+
+ // Success
+ return 0;
+}
+
+ZErrno ZBackingFile::split_and_fallocate(bool punch_hole, size_t offset, size_t length) {
+ // Try first half
+ const size_t offset0 = offset;
+ const size_t length0 = align_up(length / 2, _block_size);
+ const ZErrno err0 = fallocate(punch_hole, offset0, length0);
+ if (err0) {
+ return err0;
+ }
+
+ // Try second half
+ const size_t offset1 = offset0 + length0;
+ const size_t length1 = length - length0;
+ const ZErrno err1 = fallocate(punch_hole, offset1, length1);
+ if (err1) {
+ return err1;
}
- if (addr == MAP_FAILED) {
- // Not enough huge pages left
- ZErrno err;
- log_error(gc)("Failed to map backing file (%s)", err.to_string());
+ // Success
+ return 0;
+}
+
+ZErrno ZBackingFile::fallocate(bool punch_hole, size_t offset, size_t length) {
+ assert(is_aligned(offset, _block_size), "Invalid offset");
+ assert(is_aligned(length, _block_size), "Invalid length");
+
+ const ZErrno err = punch_hole ? fallocate_punch_hole(offset, length) : fallocate_fill_hole(offset, length);
+ if (err == EINTR && length > _block_size) {
+ // Calling fallocate(2) with a large length can take a long time to
+ // complete. When running profilers, such as VTune, this syscall will
+ // be constantly interrupted by signals. Expanding the file in smaller
+ // steps avoids this problem.
+ return split_and_fallocate(punch_hole, offset, length);
+ }
+
+ return err;
+}
+
+bool ZBackingFile::commit_inner(size_t offset, size_t length) {
+ log_trace(gc, heap)("Committing memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)",
+ offset / M, (offset + length) / M, length / M);
+
+retry:
+ const ZErrno err = fallocate(false /* punch_hole */, offset, length);
+ if (err) {
+ if (err == ENOSPC && !is_init_completed() && is_hugetlbfs() && z_fallocate_hugetlbfs_attempts-- > 0) {
+ // If we fail to allocate during initialization, due to lack of space on
+ // the hugetlbfs filesystem, then we wait and retry a few times before
+ // giving up. Otherwise there is a risk that running JVMs back-to-back
+ // will fail, since there is a delay between process termination and the
+ // huge pages owned by that process being returned to the huge page pool
+ // and made available for new allocations.
+ log_debug(gc, init)("Failed to commit memory (%s), retrying", err.to_string());
+
+ // Wait and retry in one second, in the hope that huge pages will be
+ // available by then.
+ sleep(1);
+ goto retry;
+ }
+
+ // Failed
+ log_error(gc)("Failed to commit memory (%s)", err.to_string());
return false;
}
- // Successful mapping, unmap again. From now on the pages we mapped
- // will be reserved for this file.
- if (munmap(addr, length) == -1) {
- ZErrno err;
- log_error(gc)("Failed to unmap backing file (%s)", err.to_string());
- return false;
- }
-
+ // Success
return true;
}
-bool ZBackingFile::try_expand_tmpfs_or_hugetlbfs(size_t offset, size_t length, size_t alignment) const {
- assert(is_aligned(offset, alignment), "Invalid offset");
- assert(is_aligned(length, alignment), "Invalid length");
+size_t ZBackingFile::commit(size_t offset, size_t length) {
+ // Try to commit the whole region
+ if (commit_inner(offset, length)) {
+ // Success
+ return length;
+ }
- log_debug(gc)("Expanding heap from " SIZE_FORMAT "M to " SIZE_FORMAT "M", offset / M, (offset + length) / M);
-
- return is_hugetlbfs() ? try_expand_hugetlbfs(offset, length) : try_expand_tmpfs(offset, length);
-}
-
-size_t ZBackingFile::try_expand(size_t offset, size_t length, size_t alignment) const {
+ // Failed, try to commit as much as possible
size_t start = offset;
size_t end = offset + length;
- // Try to expand
- if (try_expand_tmpfs_or_hugetlbfs(start, length, alignment)) {
- // Success
- return end;
- }
-
- // Failed, try to expand as much as possible
for (;;) {
- length = align_down((end - start) / 2, alignment);
- if (length < alignment) {
- // Done, don't expand more
- return start;
+ length = align_down((end - start) / 2, ZGranuleSize);
+ if (length < ZGranuleSize) {
+ // Done, don't commit more
+ return start - offset;
}
- if (try_expand_tmpfs_or_hugetlbfs(start, length, alignment)) {
- // Success, try expand more
+ if (commit_inner(start, length)) {
+ // Success, try commit more
start += length;
} else {
- // Failed, try expand less
+ // Failed, try commit less
end -= length;
}
}
}
+
+size_t ZBackingFile::uncommit(size_t offset, size_t length) {
+ log_trace(gc, heap)("Uncommitting memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)",
+ offset / M, (offset + length) / M, length / M);
+
+ const ZErrno err = fallocate(true /* punch_hole */, offset, length);
+ if (err) {
+ log_error(gc)("Failed to uncommit memory (%s)", err.to_string());
+ return 0;
+ }
+
+ return length;
+}
--- a/src/hotspot/os_cpu/linux_x86/gc/z/zBackingFile_linux_x86.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/os_cpu/linux_x86/gc/z/zBackingFile_linux_x86.hpp Wed May 15 13:54:43 2019 +0530
@@ -26,12 +26,14 @@
#include "memory/allocation.hpp"
+class ZErrno;
+
class ZBackingFile {
private:
- static bool _hugetlbfs_mmap_retry;
-
int _fd;
+ size_t _size;
uint64_t _filesystem;
+ size_t _block_size;
size_t _available;
bool _initialized;
@@ -43,11 +45,17 @@
bool is_hugetlbfs() const;
bool tmpfs_supports_transparent_huge_pages() const;
- bool try_split_and_expand_tmpfs(size_t offset, size_t length, size_t alignment) const;
- bool try_expand_tmpfs(size_t offset, size_t length, size_t alignment) const;
- bool try_expand_tmpfs(size_t offset, size_t length) const;
- bool try_expand_hugetlbfs(size_t offset, size_t length) const;
- bool try_expand_tmpfs_or_hugetlbfs(size_t offset, size_t length, size_t alignment) const;
+ ZErrno fallocate_compat_ftruncate(size_t size) const;
+ ZErrno fallocate_compat_mmap(size_t offset, size_t length, bool reserve_only) const;
+ ZErrno fallocate_compat_pwrite(size_t offset, size_t length) const;
+ ZErrno fallocate_fill_hole_compat(size_t offset, size_t length);
+ ZErrno fallocate_fill_hole_syscall(size_t offset, size_t length);
+ ZErrno fallocate_fill_hole(size_t offset, size_t length);
+ ZErrno fallocate_punch_hole(size_t offset, size_t length);
+ ZErrno split_and_fallocate(bool punch_hole, size_t offset, size_t length);
+ ZErrno fallocate(bool punch_hole, size_t offset, size_t length);
+
+ bool commit_inner(size_t offset, size_t length);
public:
ZBackingFile();
@@ -55,9 +63,11 @@
bool is_initialized() const;
int fd() const;
+ size_t size() const;
size_t available() const;
- size_t try_expand(size_t offset, size_t length, size_t alignment) const;
+ size_t commit(size_t offset, size_t length);
+ size_t uncommit(size_t offset, size_t length);
};
#endif // OS_CPU_LINUX_X86_GC_Z_ZBACKINGFILE_LINUX_X86_HPP
--- a/src/hotspot/os_cpu/linux_x86/gc/z/zBackingPath_linux_x86.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/os_cpu/linux_x86/gc/z/zBackingPath_linux_x86.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, 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
@@ -72,7 +72,7 @@
FILE* fd = fopen(PROC_SELF_MOUNTINFO, "r");
if (fd == NULL) {
ZErrno err;
- log_error(gc, init)("Failed to open %s: %s", PROC_SELF_MOUNTINFO, err.to_string());
+ log_error(gc)("Failed to open %s: %s", PROC_SELF_MOUNTINFO, err.to_string());
return;
}
@@ -113,10 +113,10 @@
}
// Preferred mount point not found
- log_error(gc, init)("More than one %s filesystem found:", filesystem);
+ log_error(gc)("More than one %s filesystem found:", filesystem);
ZArrayIterator<char*> iter2(mountpoints);
for (char* mountpoint; iter2.next(&mountpoint);) {
- log_error(gc, init)(" %s", mountpoint);
+ log_error(gc)(" %s", mountpoint);
}
return NULL;
@@ -130,7 +130,7 @@
if (mountpoints.size() == 0) {
// No mount point found
- log_error(gc, init)("Failed to find an accessible %s filesystem", filesystem);
+ log_error(gc)("Failed to find an accessible %s filesystem", filesystem);
} else if (mountpoints.size() == 1) {
// One mount point found
path = strdup(mountpoints.at(0));
--- a/src/hotspot/os_cpu/linux_x86/gc/z/zPhysicalMemoryBacking_linux_x86.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/os_cpu/linux_x86/gc/z/zPhysicalMemoryBacking_linux_x86.cpp Wed May 15 13:54:43 2019 +0530
@@ -32,6 +32,7 @@
#include "gc/z/zPhysicalMemory.inline.hpp"
#include "gc/z/zPhysicalMemoryBacking_linux_x86.hpp"
#include "logging/log.hpp"
+#include "runtime/init.hpp"
#include "runtime/os.hpp"
#include "utilities/align.hpp"
#include "utilities/debug.hpp"
@@ -40,7 +41,11 @@
#include <sys/mman.h>
#include <sys/types.h>
+//
// Support for building on older Linux systems
+//
+
+// madvise(2) flags
#ifndef MADV_HUGEPAGE
#define MADV_HUGEPAGE 14
#endif
@@ -48,22 +53,37 @@
// Proc file entry for max map mount
#define ZFILENAME_PROC_MAX_MAP_COUNT "/proc/sys/vm/max_map_count"
-ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity) :
- _manager(),
- _file() {
+bool ZPhysicalMemoryBacking::is_initialized() const {
+ return _file.is_initialized();
+}
- if (!_file.is_initialized()) {
+void ZPhysicalMemoryBacking::warn_available_space(size_t max) const {
+ // Note that the available space on a tmpfs or a hugetlbfs filesystem
+ // will be zero if no size limit was specified when it was mounted.
+ const size_t available = _file.available();
+ if (available == 0) {
+ // No size limit set, skip check
+ log_info(gc, init)("Available space on backing filesystem: N/A");
return;
}
- // Check and warn if max map count is too low
- check_max_map_count(max_capacity);
+ log_info(gc, init)("Available space on backing filesystem: " SIZE_FORMAT "M", available / M);
- // Check and warn if available space on filesystem is too low
- check_available_space_on_filesystem(max_capacity);
+ // Warn if the filesystem doesn't currently have enough space available to hold
+ // the max heap size. The max heap size will be capped if we later hit this limit
+ // when trying to expand the heap.
+ if (available < max) {
+ log_warning(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
+ log_warning(gc)("Not enough space available on the backing filesystem to hold the current max Java heap");
+ log_warning(gc)("size (" SIZE_FORMAT "M). Please adjust the size of the backing filesystem accordingly "
+ "(available", max / M);
+ log_warning(gc)("space is currently " SIZE_FORMAT "M). Continuing execution with the current filesystem "
+ "size could", available / M);
+ log_warning(gc)("lead to a premature OutOfMemoryError being thrown, due to failure to map memory.");
+ }
}
-void ZPhysicalMemoryBacking::check_max_map_count(size_t max_capacity) const {
+void ZPhysicalMemoryBacking::warn_max_map_count(size_t max) const {
const char* const filename = ZFILENAME_PROC_MAX_MAP_COUNT;
FILE* const file = fopen(filename, "r");
if (file == NULL) {
@@ -86,62 +106,101 @@
// However, ZGC tends to create the most mappings and dominate the total count.
// In the worst cases, ZGC will map each granule three times, i.e. once per heap view.
// We speculate that we need another 20% to allow for non-ZGC subsystems to map memory.
- const size_t required_max_map_count = (max_capacity / ZGranuleSize) * 3 * 1.2;
+ const size_t required_max_map_count = (max / ZGranuleSize) * 3 * 1.2;
if (actual_max_map_count < required_max_map_count) {
- log_warning(gc, init)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
- log_warning(gc, init)("The system limit on number of memory mappings per process might be too low "
- "for the given");
- log_warning(gc, init)("max Java heap size (" SIZE_FORMAT "M). Please adjust %s to allow for at",
- max_capacity / M, filename);
- log_warning(gc, init)("least " SIZE_FORMAT " mappings (current limit is " SIZE_FORMAT "). Continuing "
- "execution with the current", required_max_map_count, actual_max_map_count);
- log_warning(gc, init)("limit could lead to a fatal error, due to failure to map memory.");
+ log_warning(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
+ log_warning(gc)("The system limit on number of memory mappings per process might be too low for the given");
+ log_warning(gc)("max Java heap size (" SIZE_FORMAT "M). Please adjust %s to allow for at",
+ max / M, filename);
+ log_warning(gc)("least " SIZE_FORMAT " mappings (current limit is " SIZE_FORMAT "). Continuing execution "
+ "with the current", required_max_map_count, actual_max_map_count);
+ log_warning(gc)("limit could lead to a fatal error, due to failure to map memory.");
}
}
-void ZPhysicalMemoryBacking::check_available_space_on_filesystem(size_t max_capacity) const {
- // Note that the available space on a tmpfs or a hugetlbfs filesystem
- // will be zero if no size limit was specified when it was mounted.
- const size_t available = _file.available();
- if (available == 0) {
- // No size limit set, skip check
- log_info(gc, init)("Available space on backing filesystem: N/A");
- return;
+void ZPhysicalMemoryBacking::warn_commit_limits(size_t max) const {
+ // Warn if available space is too low
+ warn_available_space(max);
+
+ // Warn if max map count is too low
+ warn_max_map_count(max);
+}
+
+bool ZPhysicalMemoryBacking::supports_uncommit() {
+ assert(!is_init_completed(), "Invalid state");
+ assert(_file.size() >= ZGranuleSize, "Invalid size");
+
+ // Test if uncommit is supported by uncommitting and then re-committing a granule
+ return commit(uncommit(ZGranuleSize)) == ZGranuleSize;
+}
+
+size_t ZPhysicalMemoryBacking::commit(size_t size) {
+ size_t committed = 0;
+
+ // Fill holes in the backing file
+ while (committed < size) {
+ size_t allocated = 0;
+ const size_t remaining = size - committed;
+ const uintptr_t start = _uncommitted.alloc_from_front_at_most(remaining, &allocated);
+ if (start == UINTPTR_MAX) {
+ // No holes to commit
+ break;
+ }
+
+ // Try commit hole
+ const size_t filled = _file.commit(start, allocated);
+ if (filled > 0) {
+ // Successful or partialy successful
+ _committed.free(start, filled);
+ committed += filled;
+ }
+ if (filled < allocated) {
+ // Failed or partialy failed
+ _uncommitted.free(start + filled, allocated - filled);
+ return committed;
+ }
}
- log_info(gc, init)("Available space on backing filesystem: " SIZE_FORMAT "M",
- available / M);
+ // Expand backing file
+ if (committed < size) {
+ const size_t remaining = size - committed;
+ const uintptr_t start = _file.size();
+ const size_t expanded = _file.commit(start, remaining);
+ if (expanded > 0) {
+ // Successful or partialy successful
+ _committed.free(start, expanded);
+ committed += expanded;
+ }
+ }
- // Warn if the filesystem doesn't currently have enough space available to hold
- // the max heap size. The max heap size will be capped if we later hit this limit
- // when trying to expand the heap.
- if (available < max_capacity) {
- log_warning(gc, init)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
- log_warning(gc, init)("Not enough space available on the backing filesystem to hold the current "
- "max Java heap");
- log_warning(gc, init)("size (" SIZE_FORMAT "M). Please adjust the size of the backing filesystem "
- "accordingly (available", max_capacity / M);
- log_warning(gc, init)("space is currently " SIZE_FORMAT "M). Continuing execution with the current "
- "filesystem size could", available / M);
- log_warning(gc, init)("lead to a premature OutOfMemoryError being thrown, due to failure to map "
- "memory.");
- }
+ return committed;
}
-bool ZPhysicalMemoryBacking::is_initialized() const {
- return _file.is_initialized();
-}
+size_t ZPhysicalMemoryBacking::uncommit(size_t size) {
+ size_t uncommitted = 0;
+
+ // Punch holes in backing file
+ while (uncommitted < size) {
+ size_t allocated = 0;
+ const size_t remaining = size - uncommitted;
+ const uintptr_t start = _committed.alloc_from_back_at_most(remaining, &allocated);
+ assert(start != UINTPTR_MAX, "Allocation should never fail");
-size_t ZPhysicalMemoryBacking::try_expand(size_t old_capacity, size_t new_capacity) {
- assert(old_capacity < new_capacity, "Invalid old/new capacity");
-
- const size_t capacity = _file.try_expand(old_capacity, new_capacity - old_capacity, ZGranuleSize);
- if (capacity > old_capacity) {
- // Add expanded capacity to free list
- _manager.free(old_capacity, capacity - old_capacity);
+ // Try punch hole
+ const size_t punched = _file.uncommit(start, allocated);
+ if (punched > 0) {
+ // Successful or partialy successful
+ _uncommitted.free(start, punched);
+ uncommitted += punched;
+ }
+ if (punched < allocated) {
+ // Failed or partialy failed
+ _committed.free(start + punched, allocated - punched);
+ return uncommitted;
+ }
}
- return capacity;
+ return uncommitted;
}
ZPhysicalMemory ZPhysicalMemoryBacking::alloc(size_t size) {
@@ -151,7 +210,7 @@
// Allocate segments
for (size_t allocated = 0; allocated < size; allocated += ZGranuleSize) {
- const uintptr_t start = _manager.alloc_from_front(ZGranuleSize);
+ const uintptr_t start = _committed.alloc_from_front(ZGranuleSize);
assert(start != UINTPTR_MAX, "Allocation should never fail");
pmem.add_segment(ZPhysicalMemorySegment(start, ZGranuleSize));
}
@@ -159,13 +218,13 @@
return pmem;
}
-void ZPhysicalMemoryBacking::free(ZPhysicalMemory pmem) {
+void ZPhysicalMemoryBacking::free(const ZPhysicalMemory& pmem) {
const size_t nsegments = pmem.nsegments();
// Free segments
for (size_t i = 0; i < nsegments; i++) {
- const ZPhysicalMemorySegment segment = pmem.segment(i);
- _manager.free(segment.start(), segment.size());
+ const ZPhysicalMemorySegment& segment = pmem.segment(i);
+ _committed.free(segment.start(), segment.size());
}
}
@@ -178,10 +237,10 @@
}
}
-void ZPhysicalMemoryBacking::advise_view(uintptr_t addr, size_t size) const {
- if (madvise((void*)addr, size, MADV_HUGEPAGE) == -1) {
+void ZPhysicalMemoryBacking::advise_view(uintptr_t addr, size_t size, int advice) const {
+ if (madvise((void*)addr, size, advice) == -1) {
ZErrno err;
- log_error(gc)("Failed to advise use of transparent huge pages (%s)", err.to_string());
+ log_error(gc)("Failed to advise on memory (advice %d, %s)", advice, err.to_string());
}
}
@@ -190,41 +249,42 @@
os::pretouch_memory((void*)addr, (void*)(addr + size), page_size);
}
-void ZPhysicalMemoryBacking::map_view(ZPhysicalMemory pmem, uintptr_t addr, bool pretouch) const {
+void ZPhysicalMemoryBacking::map_view(const ZPhysicalMemory& pmem, uintptr_t addr, bool pretouch) const {
const size_t nsegments = pmem.nsegments();
+ size_t size = 0;
// Map segments
for (size_t i = 0; i < nsegments; i++) {
- const ZPhysicalMemorySegment segment = pmem.segment(i);
- const size_t size = segment.size();
- const void* const res = mmap((void*)addr, size, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, _file.fd(), segment.start());
+ const ZPhysicalMemorySegment& segment = pmem.segment(i);
+ const uintptr_t segment_addr = addr + size;
+ const void* const res = mmap((void*)segment_addr, segment.size(), PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, _file.fd(), segment.start());
if (res == MAP_FAILED) {
ZErrno err;
map_failed(err);
}
- // Advise on use of transparent huge pages before touching it
- if (ZLargePages::is_transparent()) {
- advise_view(addr, size);
- }
+ size += segment.size();
+ }
- // NUMA interleave memory before touching it
- ZNUMA::memory_interleave(addr, size);
+ // Advise on use of transparent huge pages before touching it
+ if (ZLargePages::is_transparent()) {
+ advise_view(addr, size, MADV_HUGEPAGE);
+ }
- if (pretouch) {
- pretouch_view(addr, size);
- }
+ // NUMA interleave memory before touching it
+ ZNUMA::memory_interleave(addr, size);
- addr += size;
+ // Pre-touch memory
+ if (pretouch) {
+ pretouch_view(addr, size);
}
}
-void ZPhysicalMemoryBacking::unmap_view(ZPhysicalMemory pmem, uintptr_t addr) const {
+void ZPhysicalMemoryBacking::unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const {
// Note that we must keep the address space reservation intact and just detach
// the backing memory. For this reason we map a new anonymous, non-accessible
// and non-reserved page over the mapping instead of actually unmapping.
- const size_t size = pmem.size();
- const void* const res = mmap((void*)addr, size, PROT_NONE, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
+ const void* const res = mmap((void*)addr, pmem.size(), PROT_NONE, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
if (res == MAP_FAILED) {
ZErrno err;
map_failed(err);
@@ -232,11 +292,11 @@
}
uintptr_t ZPhysicalMemoryBacking::nmt_address(uintptr_t offset) const {
- // From an NMT point of view we treat the first heap mapping (marked0) as committed
+ // From an NMT point of view we treat the first heap view (marked0) as committed
return ZAddress::marked0(offset);
}
-void ZPhysicalMemoryBacking::map(ZPhysicalMemory pmem, uintptr_t offset) const {
+void ZPhysicalMemoryBacking::map(const ZPhysicalMemory& pmem, uintptr_t offset) const {
if (ZVerifyViews) {
// Map good view
map_view(pmem, ZAddress::good(offset), AlwaysPreTouch);
@@ -248,7 +308,7 @@
}
}
-void ZPhysicalMemoryBacking::unmap(ZPhysicalMemory pmem, uintptr_t offset) const {
+void ZPhysicalMemoryBacking::unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const {
if (ZVerifyViews) {
// Unmap good view
unmap_view(pmem, ZAddress::good(offset));
@@ -260,13 +320,13 @@
}
}
-void ZPhysicalMemoryBacking::debug_map(ZPhysicalMemory pmem, uintptr_t offset) const {
+void ZPhysicalMemoryBacking::debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const {
// Map good view
assert(ZVerifyViews, "Should be enabled");
map_view(pmem, ZAddress::good(offset), false /* pretouch */);
}
-void ZPhysicalMemoryBacking::debug_unmap(ZPhysicalMemory pmem, uintptr_t offset) const {
+void ZPhysicalMemoryBacking::debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const {
// Unmap good view
assert(ZVerifyViews, "Should be enabled");
unmap_view(pmem, ZAddress::good(offset));
--- a/src/hotspot/os_cpu/linux_x86/gc/z/zPhysicalMemoryBacking_linux_x86.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/os_cpu/linux_x86/gc/z/zPhysicalMemoryBacking_linux_x86.hpp Wed May 15 13:54:43 2019 +0530
@@ -32,35 +32,39 @@
class ZPhysicalMemoryBacking {
private:
- ZMemoryManager _manager;
ZBackingFile _file;
+ ZMemoryManager _committed;
+ ZMemoryManager _uncommitted;
- void check_max_map_count(size_t max_capacity) const;
- void check_available_space_on_filesystem(size_t max_capacity) const;
+ void warn_available_space(size_t max) const;
+ void warn_max_map_count(size_t max) const;
+
void map_failed(ZErrno err) const;
- void advise_view(uintptr_t addr, size_t size) const;
+ void advise_view(uintptr_t addr, size_t size, int advice) const;
void pretouch_view(uintptr_t addr, size_t size) const;
- void map_view(ZPhysicalMemory pmem, uintptr_t addr, bool pretouch) const;
- void unmap_view(ZPhysicalMemory pmem, uintptr_t addr) const;
+ void map_view(const ZPhysicalMemory& pmem, uintptr_t addr, bool pretouch) const;
+ void unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const;
public:
- ZPhysicalMemoryBacking(size_t max_capacity);
-
bool is_initialized() const;
- size_t try_expand(size_t old_capacity, size_t new_capacity);
+ void warn_commit_limits(size_t max) const;
+ bool supports_uncommit();
+
+ size_t commit(size_t size);
+ size_t uncommit(size_t size);
ZPhysicalMemory alloc(size_t size);
- void free(ZPhysicalMemory pmem);
+ void free(const ZPhysicalMemory& pmem);
uintptr_t nmt_address(uintptr_t offset) const;
- void map(ZPhysicalMemory pmem, uintptr_t offset) const;
- void unmap(ZPhysicalMemory pmem, uintptr_t offset) const;
+ void map(const ZPhysicalMemory& pmem, uintptr_t offset) const;
+ void unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const;
- void debug_map(ZPhysicalMemory pmem, uintptr_t offset) const;
- void debug_unmap(ZPhysicalMemory pmem, uintptr_t offset) const;
+ void debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const;
+ void debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const;
};
#endif // OS_CPU_LINUX_X86_GC_Z_ZPHYSICALMEMORYBACKING_LINUX_X86_HPP
--- a/src/hotspot/share/aot/aotCompiledMethod.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/aot/aotCompiledMethod.cpp Wed May 15 13:54:43 2019 +0530
@@ -278,7 +278,7 @@
}
}
} else if (iter.type() == relocInfo::static_call_type ||
- iter.type() == relocInfo::opt_virtual_call_type){
+ iter.type() == relocInfo::opt_virtual_call_type) {
// Check Method* in AOT c2i stub for other calls.
Metadata* meta = (Metadata*)nativeLoadGot_at(nativePltCall_at(iter.addr())->plt_c2i_stub())->data();
if (meta != NULL) {
--- a/src/hotspot/share/ci/ciEnv.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/ci/ciEnv.cpp Wed May 15 13:54:43 2019 +0530
@@ -405,8 +405,7 @@
// This is a name from a signature. Strip off the trimmings.
// Call recursive to keep scope of strippedsym.
TempNewSymbol strippedsym = SymbolTable::new_symbol(sym->as_utf8()+1,
- sym->utf8_length()-2,
- KILL_COMPILE_ON_FATAL_(_unloaded_ciinstance_klass));
+ sym->utf8_length()-2);
ciSymbol* strippedname = get_symbol(strippedsym);
return get_klass_by_name_impl(accessing_klass, cpool, strippedname, require_local);
}
@@ -459,8 +458,7 @@
// We have an unloaded array.
// Build it on the fly if the element class exists.
TempNewSymbol elem_sym = SymbolTable::new_symbol(sym->as_utf8()+1,
- sym->utf8_length()-1,
- KILL_COMPILE_ON_FATAL_(fail_type));
+ sym->utf8_length()-1);
// Get element ciKlass recursively.
ciKlass* elem_klass =
--- a/src/hotspot/share/ci/ciReplay.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/ci/ciReplay.cpp Wed May 15 13:54:43 2019 +0530
@@ -336,7 +336,7 @@
Symbol* parse_symbol(TRAPS) {
const char* str = parse_escaped_string();
if (str != NULL) {
- Symbol* sym = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
+ Symbol* sym = SymbolTable::new_symbol(str);
return sym;
}
return NULL;
@@ -345,7 +345,7 @@
// Parse a valid klass name and look it up
Klass* parse_klass(TRAPS) {
const char* str = parse_escaped_string();
- Symbol* klass_name = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
+ Symbol* klass_name = SymbolTable::new_symbol(str);
if (klass_name != NULL) {
Klass* k = NULL;
if (_iklass != NULL) {
@@ -371,7 +371,7 @@
// Lookup a klass
Klass* resolve_klass(const char* klass, TRAPS) {
- Symbol* klass_name = SymbolTable::lookup(klass, (int)strlen(klass), CHECK_NULL);
+ Symbol* klass_name = SymbolTable::new_symbol(klass);
return SystemDictionary::resolve_or_fail(klass_name, _loader, _protection_domain, true, THREAD);
}
@@ -800,8 +800,8 @@
const char* field_name = parse_escaped_string();
const char* field_signature = parse_string();
fieldDescriptor fd;
- Symbol* name = SymbolTable::lookup(field_name, (int)strlen(field_name), CHECK);
- Symbol* sig = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK);
+ Symbol* name = SymbolTable::new_symbol(field_name);
+ Symbol* sig = SymbolTable::new_symbol(field_signature);
if (!k->find_local_field(name, sig, &fd) ||
!fd.is_static() ||
fd.has_initial_value()) {
--- a/src/hotspot/share/ci/ciSignature.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/ci/ciSignature.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -58,16 +58,9 @@
if (!ss.is_object()) {
type = ciType::make(ss.type());
} else {
- Symbol* name = ss.as_symbol(THREAD);
- if (HAS_PENDING_EXCEPTION) {
- type = ss.is_array() ? (ciType*)ciEnv::unloaded_ciobjarrayklass()
- : (ciType*)ciEnv::unloaded_ciinstance_klass();
- env->record_out_of_memory_failure();
- CLEAR_PENDING_EXCEPTION;
- } else {
- ciSymbol* klass_name = env->get_symbol(name);
- type = env->get_klass_by_name_impl(_accessing_klass, cpool, klass_name, false);
- }
+ Symbol* name = ss.as_symbol();
+ ciSymbol* klass_name = env->get_symbol(name);
+ type = env->get_klass_by_name_impl(_accessing_klass, cpool, klass_name, false);
}
_types->append(type);
if (ss.at_return_type()) {
--- a/src/hotspot/share/ci/ciSymbol.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/ci/ciSymbol.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -132,12 +132,7 @@
// Make a ciSymbol from a C string (implementation).
ciSymbol* ciSymbol::make_impl(const char* s) {
EXCEPTION_CONTEXT;
- TempNewSymbol sym = SymbolTable::new_symbol(s, THREAD);
- if (HAS_PENDING_EXCEPTION) {
- CLEAR_PENDING_EXCEPTION;
- CURRENT_THREAD_ENV->record_out_of_memory_failure();
- return ciEnv::_unloaded_cisymbol;
- }
+ TempNewSymbol sym = SymbolTable::new_symbol(s);
return CURRENT_THREAD_ENV->get_symbol(sym);
}
--- a/src/hotspot/share/classfile/classFileParser.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/classFileParser.cpp Wed May 15 13:54:43 2019 +0530
@@ -335,8 +335,7 @@
names,
lengths,
indices,
- hashValues,
- CHECK);
+ hashValues);
names_count = 0;
}
} else {
@@ -373,8 +372,7 @@
names,
lengths,
indices,
- hashValues,
- CHECK);
+ hashValues);
}
// Copy _current pointer of local copy back to stream.
@@ -823,7 +821,7 @@
guarantee_property(java_lang_String::is_instance(patch()),
"Illegal class patch at %d in class file %s",
index, CHECK);
- Symbol* const name = java_lang_String::as_symbol(patch(), CHECK);
+ Symbol* const name = java_lang_String::as_symbol(patch());
patch_class(cp, index, NULL, name);
}
break;
@@ -5723,7 +5721,7 @@
// The new class name is created with a refcount of one. When installed into the InstanceKlass,
// it'll be two and when the ClassFileParser destructor runs, it'll go back to one and get deleted
// when the class is unloaded.
- _class_name = SymbolTable::new_symbol(new_anon_name, symbol_len, CHECK);
+ _class_name = SymbolTable::new_symbol(new_anon_name, symbol_len);
}
}
--- a/src/hotspot/share/classfile/classListParser.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/classListParser.cpp Wed May 15 13:54:43 2019 +0530
@@ -326,8 +326,7 @@
}
Klass* ClassListParser::load_current_class(TRAPS) {
- TempNewSymbol class_name_symbol = SymbolTable::new_symbol(_class_name, THREAD);
- guarantee(!HAS_PENDING_EXCEPTION, "Exception creating a symbol.");
+ TempNewSymbol class_name_symbol = SymbolTable::new_symbol(_class_name);
Klass *klass = NULL;
if (!is_loading_from_source()) {
--- a/src/hotspot/share/classfile/classLoader.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/classLoader.cpp Wed May 15 13:54:43 2019 +0530
@@ -244,7 +244,7 @@
return NULL;
}
PackageEntryTable* pkgEntryTable = loader_data->packages();
- TempNewSymbol pkg_symbol = SymbolTable::new_symbol(pkg_name, CHECK_NULL);
+ TempNewSymbol pkg_symbol = SymbolTable::new_symbol(pkg_name);
return pkgEntryTable->lookup_only(pkg_symbol);
}
@@ -646,7 +646,7 @@
for (int i = 0; i < num_of_entries; i++) {
const char* module_name = (patch_mod_args->at(i))->module_name();
- Symbol* const module_sym = SymbolTable::lookup(module_name, (int)strlen(module_name), CHECK);
+ Symbol* const module_sym = SymbolTable::new_symbol(module_name);
assert(module_sym != NULL, "Failed to obtain Symbol for module name");
ModuleClassPathList* module_cpl = new ModuleClassPathList(module_sym);
@@ -1126,7 +1126,7 @@
const char *cp = package_from_name(fullq_class_name);
if (cp != NULL) {
PackageEntryTable* pkg_entry_tbl = ClassLoaderData::the_null_class_loader_data()->packages();
- TempNewSymbol pkg_symbol = SymbolTable::new_symbol(cp, CHECK_false);
+ TempNewSymbol pkg_symbol = SymbolTable::new_symbol(cp);
PackageEntry* pkg_entry = pkg_entry_tbl->lookup_only(pkg_symbol);
if (pkg_entry != NULL) {
assert(classpath_index != -1, "Unexpected classpath_index");
@@ -1141,7 +1141,7 @@
oop ClassLoader::get_system_package(const char* name, TRAPS) {
// Look up the name in the boot loader's package entry table.
if (name != NULL) {
- TempNewSymbol package_sym = SymbolTable::new_symbol(name, (int)strlen(name), CHECK_NULL);
+ TempNewSymbol package_sym = SymbolTable::new_symbol(name);
// Look for the package entry in the boot loader's package entry table.
PackageEntry* package =
ClassLoaderData::the_null_class_loader_data()->packages()->lookup_only(package_sym);
--- a/src/hotspot/share/classfile/classLoaderData.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/classLoaderData.cpp Wed May 15 13:54:43 2019 +0530
@@ -108,8 +108,7 @@
const char* cl_instance_name = java_lang_String::as_utf8_string(cl_name);
if (cl_instance_name != NULL && cl_instance_name[0] != '\0') {
- // Can't throw InternalError and SymbolTable doesn't throw OOM anymore.
- _name = SymbolTable::new_symbol(cl_instance_name, CATCH);
+ _name = SymbolTable::new_symbol(cl_instance_name);
}
}
@@ -125,8 +124,7 @@
(cl_name_and_id == NULL) ? _class_loader_klass->external_name() :
java_lang_String::as_utf8_string(cl_name_and_id);
assert(cl_instance_name_and_id != NULL && cl_instance_name_and_id[0] != '\0', "class loader has no name and id");
- // Can't throw InternalError and SymbolTable doesn't throw OOM anymore.
- _name_and_id = SymbolTable::new_symbol(cl_instance_name_and_id, CATCH);
+ _name_and_id = SymbolTable::new_symbol(cl_instance_name_and_id);
}
ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_unsafe_anonymous) :
--- a/src/hotspot/share/classfile/classLoaderData.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/classLoaderData.hpp Wed May 15 13:54:43 2019 +0530
@@ -300,6 +300,10 @@
ModuleEntryTable* modules();
bool modules_defined() { return (_modules != NULL); }
+ // Offsets
+ static ByteSize holder_offset() { return in_ByteSize(offset_of(ClassLoaderData, _holder)); }
+ static ByteSize keep_alive_offset() { return in_ByteSize(offset_of(ClassLoaderData, _keep_alive)); }
+
// Loaded class dictionary
Dictionary* dictionary() const { return _dictionary; }
--- a/src/hotspot/share/classfile/defaultMethods.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/defaultMethods.cpp Wed May 15 13:54:43 2019 +0530
@@ -459,7 +459,7 @@
};
Symbol* MethodFamily::generate_no_defaults_message(TRAPS) const {
- return SymbolTable::new_symbol("No qualifying defaults found", THREAD);
+ return SymbolTable::new_symbol("No qualifying defaults found");
}
Symbol* MethodFamily::generate_method_message(Symbol *klass_name, Method* method, TRAPS) const {
@@ -472,7 +472,7 @@
ss.write((const char*)name->bytes(), name->utf8_length());
ss.write((const char*)signature->bytes(), signature->utf8_length());
ss.print(" is abstract");
- return SymbolTable::new_symbol(ss.base(), (int)ss.size(), THREAD);
+ return SymbolTable::new_symbol(ss.base(), (int)ss.size());
}
Symbol* MethodFamily::generate_conflicts_message(GrowableArray<Method*>* methods, TRAPS) const {
@@ -487,7 +487,7 @@
ss.print(".");
ss.write((const char*)name->bytes(), name->utf8_length());
}
- return SymbolTable::new_symbol(ss.base(), (int)ss.size(), THREAD);
+ return SymbolTable::new_symbol(ss.base(), (int)ss.size());
}
--- a/src/hotspot/share/classfile/javaClasses.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/javaClasses.cpp Wed May 15 13:54:43 2019 +0530
@@ -569,19 +569,19 @@
return result;
}
-Symbol* java_lang_String::as_symbol(oop java_string, TRAPS) {
+Symbol* java_lang_String::as_symbol(oop java_string) {
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);
if (!is_latin1) {
jchar* base = (length == 0) ? NULL : value->char_at_addr(0);
- Symbol* sym = SymbolTable::lookup_unicode(base, length, THREAD);
+ Symbol* sym = SymbolTable::new_symbol(base, length);
return sym;
} else {
ResourceMark rm;
jbyte* position = (length == 0) ? NULL : value->byte_at_addr(0);
const char* base = UNICODE::as_utf8(position, length);
- Symbol* sym = SymbolTable::lookup(base, length, THREAD);
+ Symbol* sym = SymbolTable::new_symbol(base, length);
return sym;
}
}
@@ -1443,7 +1443,7 @@
if (is_instance) st->print(";");
}
-Symbol* java_lang_Class::as_signature(oop java_class, bool intern_if_not_found, TRAPS) {
+Symbol* java_lang_Class::as_signature(oop java_class, bool intern_if_not_found) {
assert(java_lang_Class::is_instance(java_class), "must be a Class object");
Symbol* name;
if (is_primitive(java_class)) {
@@ -1464,7 +1464,7 @@
if (!intern_if_not_found) {
name = SymbolTable::probe(sigstr, siglen);
} else {
- name = SymbolTable::new_symbol(sigstr, siglen, THREAD);
+ name = SymbolTable::new_symbol(sigstr, siglen);
}
}
}
@@ -1895,7 +1895,7 @@
PRESERVE_EXCEPTION_MARK; // Keep original exception
oop detailed_message = java_lang_Throwable::message(throwable);
if (detailed_message != NULL) {
- return java_lang_String::as_symbol(detailed_message, THREAD);
+ return java_lang_String::as_symbol(detailed_message);
}
return NULL;
}
@@ -3703,7 +3703,7 @@
java_lang_Class::print_signature(rtype(mt), st);
}
-Symbol* java_lang_invoke_MethodType::as_signature(oop mt, bool intern_if_not_found, TRAPS) {
+Symbol* java_lang_invoke_MethodType::as_signature(oop mt, bool intern_if_not_found) {
ResourceMark rm;
stringStream buffer(128);
print_signature(mt, &buffer);
@@ -3713,7 +3713,7 @@
if (!intern_if_not_found) {
name = SymbolTable::probe(sigstr, siglen);
} else {
- name = SymbolTable::new_symbol(sigstr, siglen, THREAD);
+ name = SymbolTable::new_symbol(sigstr, siglen);
}
return name;
}
@@ -4375,11 +4375,11 @@
bool JavaClasses::check_offset(const char *klass_name, int hardcoded_offset, const char *field_name, const char* field_sig) {
EXCEPTION_MARK;
fieldDescriptor fd;
- TempNewSymbol klass_sym = SymbolTable::new_symbol(klass_name, CATCH);
+ TempNewSymbol klass_sym = SymbolTable::new_symbol(klass_name);
Klass* k = SystemDictionary::resolve_or_fail(klass_sym, true, CATCH);
InstanceKlass* ik = InstanceKlass::cast(k);
- TempNewSymbol f_name = SymbolTable::new_symbol(field_name, CATCH);
- TempNewSymbol f_sig = SymbolTable::new_symbol(field_sig, CATCH);
+ TempNewSymbol f_name = SymbolTable::new_symbol(field_name);
+ TempNewSymbol f_sig = SymbolTable::new_symbol(field_sig);
if (!ik->find_local_field(f_name, f_sig, &fd)) {
tty->print_cr("Nonstatic field %s.%s not found", klass_name, field_name);
return false;
--- a/src/hotspot/share/classfile/javaClasses.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/javaClasses.hpp Wed May 15 13:54:43 2019 +0530
@@ -205,7 +205,7 @@
static Handle internalize_classname(Handle java_string, TRAPS) { return char_converter(java_string, '.', '/', THREAD); }
// Conversion
- static Symbol* as_symbol(oop java_string, TRAPS);
+ static Symbol* as_symbol(oop java_string);
static Symbol* as_symbol_or_null(oop java_string);
// Testers
@@ -291,7 +291,7 @@
static Klass* as_Klass_raw(oop java_class);
static void set_klass(oop java_class, Klass* klass);
static BasicType as_BasicType(oop java_class, Klass** reference_klass = NULL);
- static Symbol* as_signature(oop java_class, bool intern_if_not_found, TRAPS);
+ static Symbol* as_signature(oop java_class, bool intern_if_not_found);
static void print_signature(oop java_class, outputStream *st);
static const char* as_external_name(oop java_class);
// Testing
@@ -1166,7 +1166,7 @@
static int ptype_slot_count(oop mt); // extra counts for long/double
static int rtype_slot_count(oop mt); // extra counts for long/double
- static Symbol* as_signature(oop mt, bool intern_if_not_found, TRAPS);
+ static Symbol* as_signature(oop mt, bool intern_if_not_found);
static void print_signature(oop mt, outputStream* st);
static bool is_instance(oop obj);
--- a/src/hotspot/share/classfile/modules.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/modules.cpp Wed May 15 13:54:43 2019 +0530
@@ -111,7 +111,7 @@
static PackageEntry* get_package_entry(ModuleEntry* module_entry, const char* package_name, TRAPS) {
ResourceMark rm(THREAD);
if (package_name == NULL) return NULL;
- TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK_NULL);
+ TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name);
PackageEntryTable* package_entry_table = module_entry->loader_data()->packages();
assert(package_entry_table != NULL, "Unexpected null package entry table");
return package_entry_table->lookup_only(pkg_symbol);
@@ -148,7 +148,7 @@
const char* module_version = get_module_version(version);
TempNewSymbol version_symbol;
if (module_version != NULL) {
- version_symbol = SymbolTable::new_symbol(module_version, CHECK);
+ version_symbol = SymbolTable::new_symbol(module_version);
} else {
version_symbol = NULL;
}
@@ -160,7 +160,7 @@
module_location =
java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(location));
if (module_location != NULL) {
- location_symbol = SymbolTable::new_symbol(module_location, CHECK);
+ location_symbol = SymbolTable::new_symbol(module_location);
}
}
@@ -173,7 +173,7 @@
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
err_msg("Invalid package name: %s for module: " JAVA_BASE_NAME, package_name));
}
- Symbol* pkg_symbol = SymbolTable::new_symbol(package_name, CHECK);
+ Symbol* pkg_symbol = SymbolTable::new_symbol(package_name);
pkg_list->append(pkg_symbol);
}
@@ -345,7 +345,7 @@
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message);
}
- Symbol* pkg_symbol = SymbolTable::new_symbol(package_name, CHECK);
+ Symbol* pkg_symbol = SymbolTable::new_symbol(package_name);
pkg_list->append(pkg_symbol);
}
@@ -353,14 +353,14 @@
assert(module_table != NULL, "module entry table shouldn't be null");
// Create symbol* entry for module name.
- TempNewSymbol module_symbol = SymbolTable::new_symbol(module_name, CHECK);
+ TempNewSymbol module_symbol = SymbolTable::new_symbol(module_name);
bool dupl_modules = false;
// Create symbol* entry for module version.
TempNewSymbol version_symbol;
if (module_version != NULL) {
- version_symbol = SymbolTable::new_symbol(module_version, CHECK);
+ version_symbol = SymbolTable::new_symbol(module_version);
} else {
version_symbol = NULL;
}
@@ -372,7 +372,7 @@
module_location =
java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(location));
if (module_location != NULL) {
- location_symbol = SymbolTable::new_symbol(module_location, CHECK);
+ location_symbol = SymbolTable::new_symbol(module_location);
}
}
@@ -657,7 +657,7 @@
if (strlen(package_name) == 0) {
return NULL;
}
- TempNewSymbol package_sym = SymbolTable::new_symbol(package_name, CHECK_NULL);
+ TempNewSymbol package_sym = SymbolTable::new_symbol(package_name);
const PackageEntry* const pkg_entry =
get_package_entry_by_name(package_sym, h_loader, THREAD);
const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL);
--- a/src/hotspot/share/classfile/stackMapFrame.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/stackMapFrame.cpp Wed May 15 13:54:43 2019 +0530
@@ -92,8 +92,7 @@
// local num may be greater than size of parameters because long/double occupies two slots
while(!ss.at_return_type()) {
init_local_num += _verifier->change_sig_to_verificationType(
- &ss, &_locals[init_local_num],
- CHECK_VERIFY_(verifier(), VerificationType::bogus_type()));
+ &ss, &_locals[init_local_num]);
ss.next();
}
_locals_size = init_local_num;
@@ -102,13 +101,12 @@
case T_OBJECT:
case T_ARRAY:
{
- Symbol* sig = ss.as_symbol(CHECK_(VerificationType::bogus_type()));
+ Symbol* sig = ss.as_symbol();
if (!sig->is_permanent()) {
// Create another symbol to save as signature stream unreferences
// this symbol.
Symbol *sig_copy =
- verifier()->create_temporary_symbol(sig, 0, sig->utf8_length(),
- CHECK_(VerificationType::bogus_type()));
+ verifier()->create_temporary_symbol(sig, 0, sig->utf8_length());
assert(sig_copy == sig, "symbols don't match");
sig = sig_copy;
}
--- a/src/hotspot/share/classfile/symbolTable.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/symbolTable.cpp Wed May 15 13:54:43 2019 +0530
@@ -195,7 +195,7 @@
Service_lock->notify_all();
}
-Symbol* SymbolTable::allocate_symbol(const char* name, int len, bool c_heap, TRAPS) {
+Symbol* SymbolTable::allocate_symbol(const char* name, int len, bool c_heap) {
assert (len <= Symbol::max_length(), "should be checked by caller");
Symbol* sym;
@@ -204,12 +204,12 @@
}
if (c_heap) {
// refcount starts as 1
- sym = new (len, THREAD) Symbol((const u1*)name, len, 1);
+ sym = new (len) Symbol((const u1*)name, len, 1);
assert(sym != NULL, "new should call vm_exit_out_of_memory if C_HEAP is exhausted");
} else {
// Allocate to global arena
MutexLocker ml(SymbolArena_lock, Mutex::_no_safepoint_check_flag); // Protect arena
- sym = new (len, arena(), THREAD) Symbol((const u1*)name, len, PERM_REFCOUNT);
+ sym = new (len, arena()) Symbol((const u1*)name, len, PERM_REFCOUNT);
}
return sym;
}
@@ -317,25 +317,26 @@
return sym;
}
-Symbol* SymbolTable::lookup(const char* name, int len, TRAPS) {
+Symbol* SymbolTable::new_symbol(const char* name, int len) {
unsigned int hash = hash_symbol(name, len, SymbolTable::_alt_hash);
Symbol* sym = SymbolTable::the_table()->lookup_common(name, len, hash);
if (sym == NULL) {
- sym = SymbolTable::the_table()->do_add_if_needed(name, len, hash, true, CHECK_NULL);
+ sym = SymbolTable::the_table()->do_add_if_needed(name, len, hash, true);
}
assert(sym->refcount() != 0, "lookup should have incremented the count");
assert(sym->equals(name, len), "symbol must be properly initialized");
return sym;
}
-Symbol* SymbolTable::lookup(const Symbol* sym, int begin, int end, TRAPS) {
+Symbol* SymbolTable::new_symbol(const Symbol* sym, int begin, int end) {
+ assert(begin <= end && end <= sym->utf8_length(), "just checking");
assert(sym->refcount() != 0, "require a valid symbol");
const char* name = (const char*)sym->base() + begin;
int len = end - begin;
unsigned int hash = hash_symbol(name, len, SymbolTable::_alt_hash);
Symbol* found = SymbolTable::the_table()->lookup_common(name, len, hash);
if (found == NULL) {
- found = SymbolTable::the_table()->do_add_if_needed(name, len, hash, true, THREAD);
+ found = SymbolTable::the_table()->do_add_if_needed(name, len, hash, true);
}
return found;
}
@@ -347,8 +348,8 @@
int _len;
const char* _str;
public:
- SymbolTableLookup(Thread* thread, const char* key, int len, uintx hash)
- : _thread(thread), _hash(hash), _len(len), _str(key) {}
+ SymbolTableLookup(const char* key, int len, uintx hash)
+ : _hash(hash), _len(len), _str(key) {}
uintx get_hash() const {
return _hash;
}
@@ -388,7 +389,7 @@
Symbol* SymbolTable::do_lookup(const char* name, int len, uintx hash) {
Thread* thread = Thread::current();
- SymbolTableLookup lookup(thread, name, len, hash);
+ SymbolTableLookup lookup(name, len, hash);
SymbolTableGet stg;
bool rehash_warning = false;
_local_table->get(thread, lookup, stg, &rehash_warning);
@@ -406,23 +407,23 @@
// Suggestion: Push unicode-based lookup all the way into the hashing
// and probing logic, so there is no need for convert_to_utf8 until
// an actual new Symbol* is created.
-Symbol* SymbolTable::lookup_unicode(const jchar* name, int utf16_length, TRAPS) {
+Symbol* SymbolTable::new_symbol(const jchar* name, int utf16_length) {
int utf8_length = UNICODE::utf8_length((jchar*) name, utf16_length);
char stack_buf[ON_STACK_BUFFER_LENGTH];
if (utf8_length < (int) sizeof(stack_buf)) {
char* chars = stack_buf;
UNICODE::convert_to_utf8(name, utf16_length, chars);
- return lookup(chars, utf8_length, THREAD);
+ return new_symbol(chars, utf8_length);
} else {
- ResourceMark rm(THREAD);
+ ResourceMark rm;
char* chars = NEW_RESOURCE_ARRAY(char, utf8_length + 1);
UNICODE::convert_to_utf8(name, utf16_length, chars);
- return lookup(chars, utf8_length, THREAD);
+ return new_symbol(chars, utf8_length);
}
}
Symbol* SymbolTable::lookup_only_unicode(const jchar* name, int utf16_length,
- unsigned int& hash) {
+ unsigned int& hash) {
int utf8_length = UNICODE::utf8_length((jchar*) name, utf16_length);
char stack_buf[ON_STACK_BUFFER_LENGTH];
if (utf8_length < (int) sizeof(stack_buf)) {
@@ -439,32 +440,33 @@
void SymbolTable::new_symbols(ClassLoaderData* loader_data, const constantPoolHandle& cp,
int names_count, const char** names, int* lengths,
- int* cp_indices, unsigned int* hashValues, TRAPS) {
+ int* cp_indices, unsigned int* hashValues) {
bool c_heap = !loader_data->is_the_null_class_loader_data();
for (int i = 0; i < names_count; i++) {
const char *name = names[i];
int len = lengths[i];
unsigned int hash = hashValues[i];
assert(SymbolTable::the_table()->lookup_shared(name, len, hash) == NULL, "must have checked already");
- Symbol* sym = SymbolTable::the_table()->do_add_if_needed(name, len, hash, c_heap, CHECK);
+ Symbol* sym = SymbolTable::the_table()->do_add_if_needed(name, len, hash, c_heap);
assert(sym->refcount() != 0, "lookup should have incremented the count");
cp->symbol_at_put(cp_indices[i], sym);
}
}
-Symbol* SymbolTable::do_add_if_needed(const char* name, int len, uintx hash, bool heap, TRAPS) {
- SymbolTableLookup lookup(THREAD, name, len, hash);
+Symbol* SymbolTable::do_add_if_needed(const char* name, int len, uintx hash, bool heap) {
+ SymbolTableLookup lookup(name, len, hash);
SymbolTableGet stg;
bool clean_hint = false;
bool rehash_warning = false;
Symbol* sym = NULL;
+ Thread* THREAD = Thread::current();
do {
if (_local_table->get(THREAD, lookup, stg, &rehash_warning)) {
sym = stg.get_res_sym();
break;
}
- sym = SymbolTable::the_table()->allocate_symbol(name, len, heap, THREAD);
+ sym = SymbolTable::the_table()->allocate_symbol(name, len, heap);
if (_local_table->insert(THREAD, lookup, sym, &rehash_warning, &clean_hint)) {
break;
}
@@ -481,12 +483,12 @@
return sym;
}
-Symbol* SymbolTable::new_permanent_symbol(const char* name, TRAPS) {
+Symbol* SymbolTable::new_permanent_symbol(const char* name) {
unsigned int hash = 0;
int len = (int)strlen(name);
Symbol* sym = SymbolTable::lookup_only(name, len, hash);
if (sym == NULL) {
- sym = SymbolTable::the_table()->do_add_if_needed(name, len, hash, false, CHECK_NULL);
+ sym = SymbolTable::the_table()->do_add_if_needed(name, len, hash, false);
}
if (!sym->is_permanent()) {
sym->make_permanent();
--- a/src/hotspot/share/classfile/symbolTable.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/symbolTable.hpp Wed May 15 13:54:43 2019 +0530
@@ -43,7 +43,7 @@
// it becomes "managed" by TempNewSymbol instances. As a handle class, TempNewSymbol
// needs to maintain proper reference counting in context of copy semantics.
//
-// In SymbolTable, new_symbol() and lookup() will create a Symbol* if not already in the
+// In SymbolTable, new_symbol() will create a Symbol* if not already in the
// symbol table and add to the symbol's reference count.
// probe() and lookup_only() will increment the refcount if symbol is found.
class TempNewSymbol : public StackObj {
@@ -139,16 +139,19 @@
SymbolTable();
- Symbol* allocate_symbol(const char* name, int len, bool c_heap, TRAPS); // Assumes no characters larger than 0x7F
+ Symbol* allocate_symbol(const char* name, int len, bool c_heap); // Assumes no characters larger than 0x7F
Symbol* do_lookup(const char* name, int len, uintx hash);
- Symbol* do_add_if_needed(const char* name, int len, uintx hash, bool heap, TRAPS);
+ Symbol* do_add_if_needed(const char* name, int len, uintx hash, bool heap);
+
+ // lookup only, won't add. Also calculate hash. Used by the ClassfileParser.
+ static Symbol* lookup_only(const char* name, int len, unsigned int& hash);
+ static Symbol* lookup_only_unicode(const jchar* name, int len, unsigned int& hash);
// Adding elements
static void new_symbols(ClassLoaderData* loader_data,
const constantPoolHandle& cp, int names_count,
const char** name, int* lengths,
- int* cp_indices, unsigned int* hashValues,
- TRAPS);
+ int* cp_indices, unsigned int* hashValues);
static Symbol* lookup_shared(const char* name, int len, unsigned int hash);
Symbol* lookup_dynamic(const char* name, int len, unsigned int hash);
@@ -190,14 +193,6 @@
static void trigger_cleanup();
// Probing
- static Symbol* lookup(const char* name, int len, TRAPS);
- // lookup only, won't add. Also calculate hash.
- static Symbol* lookup_only(const char* name, int len, unsigned int& hash);
- // adds new symbol if not found
- static Symbol* lookup(const Symbol* sym, int begin, int end, TRAPS);
- // jchar (UTF16) version of lookups
- static Symbol* lookup_unicode(const jchar* name, int len, TRAPS);
- static Symbol* lookup_only_unicode(const jchar* name, int len, unsigned int& hash);
// Needed for preloading classes in signatures when compiling.
// Returns the symbol is already present in symbol table, otherwise
// NULL. NO ALLOCATION IS GUARANTEED!
@@ -210,20 +205,18 @@
return lookup_only_unicode(name, len, ignore_hash);
}
- // Symbol creation
- static Symbol* new_symbol(const char* utf8_buffer, int length, TRAPS) {
- assert(utf8_buffer != NULL, "just checking");
- return lookup(utf8_buffer, length, THREAD);
+ // Symbol lookup and create if not found.
+ // jchar (UTF16) version of lookup
+ static Symbol* new_symbol(const jchar* name, int len);
+ // char (UTF8) versions
+ static Symbol* new_symbol(const Symbol* sym, int begin, int end);
+ static Symbol* new_symbol(const char* utf8_buffer, int length);
+ static Symbol* new_symbol(const char* name) {
+ return new_symbol(name, (int)strlen(name));
}
- static Symbol* new_symbol(const char* name, TRAPS) {
- return new_symbol(name, (int)strlen(name), THREAD);
- }
- static Symbol* new_symbol(const Symbol* sym, int begin, int end, TRAPS) {
- assert(begin <= end && end <= sym->utf8_length(), "just checking");
- return lookup(sym, begin, end, THREAD);
- }
+
// Create a symbol in the arena for symbols that are not deleted
- static Symbol* new_permanent_symbol(const char* name, TRAPS);
+ static Symbol* new_permanent_symbol(const char* name);
// Rehash the string table if it gets out of balance
static void rehash_table();
@@ -245,7 +238,6 @@
static void dump(outputStream* st, bool verbose=false);
// Debugging
static void verify();
- static void read(const char* filename, TRAPS);
// Histogram
static void print_histogram() PRODUCT_RETURN;
--- a/src/hotspot/share/classfile/systemDictionary.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/systemDictionary.cpp Wed May 15 13:54:43 2019 +0530
@@ -263,7 +263,7 @@
ResourceMark rm(THREAD);
// Ignore wrapping L and ;.
TempNewSymbol name = SymbolTable::new_symbol(class_name->as_C_string() + 1,
- class_name->utf8_length() - 2, CHECK_NULL);
+ class_name->utf8_length() - 2);
return resolve_instance_class_or_null(name, class_loader, protection_domain, THREAD);
} else {
return resolve_instance_class_or_null(class_name, class_loader, protection_domain, THREAD);
@@ -2356,7 +2356,7 @@
SignatureStream sig_strm(signature, is_method);
while (!sig_strm.is_done()) {
if (sig_strm.is_object()) {
- Symbol* sig = sig_strm.as_symbol(CHECK_NULL);
+ Symbol* sig = sig_strm.as_symbol();
if (!add_loader_constraint(sig, loader1, loader2, THREAD)) {
return sig;
}
@@ -2626,7 +2626,7 @@
mirror = ss.as_java_mirror(class_loader, protection_domain,
SignatureStream::NCDFError, CHECK_(empty));
}
- assert(mirror != NULL, "%s", ss.as_symbol(THREAD)->as_C_string());
+ assert(mirror != NULL, "%s", ss.as_symbol()->as_C_string());
if (ss.at_return_type())
rt = Handle(THREAD, mirror);
else
--- a/src/hotspot/share/classfile/verificationType.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/verificationType.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -129,13 +129,11 @@
case 'D': return VerificationType(Double);
case '[':
component = context->create_temporary_symbol(
- name(), 1, name()->utf8_length(),
- CHECK_(VerificationType::bogus_type()));
+ name(), 1, name()->utf8_length());
return VerificationType::reference_type(component);
case 'L':
component = context->create_temporary_symbol(
- name(), 2, name()->utf8_length() - 1,
- CHECK_(VerificationType::bogus_type()));
+ name(), 2, name()->utf8_length() - 1);
return VerificationType::reference_type(component);
default:
// Met an invalid type signature, e.g. [X
--- a/src/hotspot/share/classfile/verifier.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/verifier.cpp Wed May 15 13:54:43 2019 +0530
@@ -595,9 +595,9 @@
return VerificationType::reference_type(vmSymbols::java_lang_Object());
}
-TypeOrigin ClassVerifier::ref_ctx(const char* sig, TRAPS) {
+TypeOrigin ClassVerifier::ref_ctx(const char* sig) {
VerificationType vt = VerificationType::reference_type(
- create_temporary_symbol(sig, (int)strlen(sig), THREAD));
+ create_temporary_symbol(sig, (int)strlen(sig)));
return TypeOrigin::implicit(vt);
}
@@ -647,7 +647,7 @@
// Translate the signature arguments into verification types.
while (!sig_stream.at_return_type()) {
- int n = change_sig_to_verificationType(&sig_stream, sig_type, CHECK_VERIFY(this));
+ int n = change_sig_to_verificationType(&sig_stream, sig_type);
assert(n <= 2, "Unexpected signature type");
// Store verification type(s). Longs and Doubles each have two verificationTypes.
@@ -664,7 +664,7 @@
// Store verification type(s) for the return type, if there is one.
if (sig_stream.type() != T_VOID) {
- int n = change_sig_to_verificationType(&sig_stream, sig_type, CHECK_VERIFY(this));
+ int n = change_sig_to_verificationType(&sig_stream, sig_type);
assert(n <= 2, "Unexpected signature return type");
for (int y = 0; y < n; y++) {
verif_types->push(sig_type[y]);
@@ -925,7 +925,7 @@
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_int_array()) {
verify_error(ErrorContext::bad_type(bci,
- current_frame.stack_top_ctx(), ref_ctx("[I", THREAD)),
+ current_frame.stack_top_ctx(), ref_ctx("[I")),
bad_type_msg, "iaload");
return;
}
@@ -953,7 +953,7 @@
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_char_array()) {
verify_error(ErrorContext::bad_type(bci,
- current_frame.stack_top_ctx(), ref_ctx("[C", THREAD)),
+ current_frame.stack_top_ctx(), ref_ctx("[C")),
bad_type_msg, "caload");
return;
}
@@ -967,7 +967,7 @@
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_short_array()) {
verify_error(ErrorContext::bad_type(bci,
- current_frame.stack_top_ctx(), ref_ctx("[S", THREAD)),
+ current_frame.stack_top_ctx(), ref_ctx("[S")),
bad_type_msg, "saload");
return;
}
@@ -981,7 +981,7 @@
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_long_array()) {
verify_error(ErrorContext::bad_type(bci,
- current_frame.stack_top_ctx(), ref_ctx("[J", THREAD)),
+ current_frame.stack_top_ctx(), ref_ctx("[J")),
bad_type_msg, "laload");
return;
}
@@ -996,7 +996,7 @@
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_float_array()) {
verify_error(ErrorContext::bad_type(bci,
- current_frame.stack_top_ctx(), ref_ctx("[F", THREAD)),
+ current_frame.stack_top_ctx(), ref_ctx("[F")),
bad_type_msg, "faload");
return;
}
@@ -1010,7 +1010,7 @@
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_double_array()) {
verify_error(ErrorContext::bad_type(bci,
- current_frame.stack_top_ctx(), ref_ctx("[D", THREAD)),
+ current_frame.stack_top_ctx(), ref_ctx("[D")),
bad_type_msg, "daload");
return;
}
@@ -1099,7 +1099,7 @@
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_int_array()) {
verify_error(ErrorContext::bad_type(bci,
- current_frame.stack_top_ctx(), ref_ctx("[I", THREAD)),
+ current_frame.stack_top_ctx(), ref_ctx("[I")),
bad_type_msg, "iastore");
return;
}
@@ -1127,7 +1127,7 @@
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_char_array()) {
verify_error(ErrorContext::bad_type(bci,
- current_frame.stack_top_ctx(), ref_ctx("[C", THREAD)),
+ current_frame.stack_top_ctx(), ref_ctx("[C")),
bad_type_msg, "castore");
return;
}
@@ -1141,7 +1141,7 @@
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_short_array()) {
verify_error(ErrorContext::bad_type(bci,
- current_frame.stack_top_ctx(), ref_ctx("[S", THREAD)),
+ current_frame.stack_top_ctx(), ref_ctx("[S")),
bad_type_msg, "sastore");
return;
}
@@ -1156,7 +1156,7 @@
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_long_array()) {
verify_error(ErrorContext::bad_type(bci,
- current_frame.stack_top_ctx(), ref_ctx("[J", THREAD)),
+ current_frame.stack_top_ctx(), ref_ctx("[J")),
bad_type_msg, "lastore");
return;
}
@@ -1170,7 +1170,7 @@
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_float_array()) {
verify_error(ErrorContext::bad_type(bci,
- current_frame.stack_top_ctx(), ref_ctx("[F", THREAD)),
+ current_frame.stack_top_ctx(), ref_ctx("[F")),
bad_type_msg, "fastore");
return;
}
@@ -1185,7 +1185,7 @@
VerificationType::reference_check(), CHECK_VERIFY(this));
if (!atype.is_double_array()) {
verify_error(ErrorContext::bad_type(bci,
- current_frame.stack_top_ctx(), ref_ctx("[D", THREAD)),
+ current_frame.stack_top_ctx(), ref_ctx("[D")),
bad_type_msg, "dastore");
return;
}
@@ -2183,8 +2183,7 @@
uintptr_t constant_type_buffer[2];
VerificationType* v_constant_type = (VerificationType*)constant_type_buffer;
SignatureStream sig_stream(constant_type, false);
- int n = change_sig_to_verificationType(
- &sig_stream, v_constant_type, CHECK_VERIFY(this));
+ int n = change_sig_to_verificationType(&sig_stream, v_constant_type);
int opcode_n = (opcode == Bytecodes::_ldc2_w ? 2 : 1);
if (n != opcode_n) {
// wrong kind of ldc; reverify against updated type mask
@@ -2325,8 +2324,7 @@
SignatureStream sig_stream(field_sig, false);
VerificationType stack_object_type;
- int n = change_sig_to_verificationType(
- &sig_stream, field_type, CHECK_VERIFY(this));
+ int n = change_sig_to_verificationType(&sig_stream, field_type);
u2 bci = bcs->bci();
bool is_assignable;
switch (bcs->raw_code()) {
@@ -3002,8 +3000,7 @@
}
// from_bt[index] contains the array signature which has a length of 2
- Symbol* sig = create_temporary_symbol(
- from_bt[index], 2, CHECK_(VerificationType::bogus_type()));
+ Symbol* sig = create_temporary_symbol(from_bt[index], 2);
return VerificationType::reference_type(sig);
}
@@ -3041,8 +3038,7 @@
int n = os::snprintf(arr_sig_str, length + 1, "[L%s;", component_name);
assert(n == length, "Unexpected number of characters in string");
}
- Symbol* arr_sig = create_temporary_symbol(
- arr_sig_str, length, CHECK_VERIFY(this));
+ Symbol* arr_sig = create_temporary_symbol(arr_sig_str, length);
VerificationType new_array_type = VerificationType::reference_type(arr_sig);
current_frame->push_stack(new_array_type, CHECK_VERIFY(this));
}
@@ -3150,18 +3146,18 @@
// These are stored in the verifier until the end of verification so that
// they can be reference counted.
Symbol* ClassVerifier::create_temporary_symbol(const Symbol *s, int begin,
- int end, TRAPS) {
+ int end) {
const char* name = (const char*)s->base() + begin;
int length = end - begin;
- return create_temporary_symbol(name, length, CHECK_NULL);
+ return create_temporary_symbol(name, length);
}
-Symbol* ClassVerifier::create_temporary_symbol(const char *name, int length, TRAPS) {
+Symbol* ClassVerifier::create_temporary_symbol(const char *name, int length) {
// Quick deduplication check
if (_previous_symbol != NULL && _previous_symbol->equals(name, length)) {
return _previous_symbol;
}
- Symbol* sym = SymbolTable::new_symbol(name, length, CHECK_NULL);
+ Symbol* sym = SymbolTable::new_symbol(name, length);
if (!sym->is_permanent()) {
if (_symbols == NULL) {
_symbols = new GrowableArray<Symbol*>(50, 0, NULL);
--- a/src/hotspot/share/classfile/verifier.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/verifier.hpp Wed May 15 13:54:43 2019 +0530
@@ -446,7 +446,7 @@
}
int change_sig_to_verificationType(
- SignatureStream* sig_type, VerificationType* inference_type, TRAPS);
+ SignatureStream* sig_type, VerificationType* inference_type);
VerificationType cp_index_to_type(int index, const constantPoolHandle& cp, TRAPS) {
return VerificationType::reference_type(cp->klass_name_at(index));
@@ -456,8 +456,8 @@
// their reference counts need to be decremented when the verifier object
// goes out of scope. Since these symbols escape the scope in which they're
// created, we can't use a TempNewSymbol.
- Symbol* create_temporary_symbol(const Symbol* s, int begin, int end, TRAPS);
- Symbol* create_temporary_symbol(const char *s, int length, TRAPS);
+ Symbol* create_temporary_symbol(const Symbol* s, int begin, int end);
+ Symbol* create_temporary_symbol(const char *s, int length);
Symbol* create_temporary_symbol(Symbol* s) {
if (s == _previous_symbol) {
return s;
@@ -473,18 +473,18 @@
return s;
}
- TypeOrigin ref_ctx(const char* str, TRAPS);
+ TypeOrigin ref_ctx(const char* str);
};
inline int ClassVerifier::change_sig_to_verificationType(
- SignatureStream* sig_type, VerificationType* inference_type, TRAPS) {
+ SignatureStream* sig_type, VerificationType* inference_type) {
BasicType bt = sig_type->type();
switch (bt) {
case T_OBJECT:
case T_ARRAY:
{
- Symbol* name = sig_type->as_symbol(CHECK_0);
+ Symbol* name = sig_type->as_symbol();
// Create another symbol to save as signature stream unreferences this symbol.
Symbol* name_copy = create_temporary_symbol(name);
assert(name_copy == name, "symbols don't match");
--- a/src/hotspot/share/classfile/vmSymbols.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/classfile/vmSymbols.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -84,7 +84,7 @@
if (!UseSharedSpaces) {
const char* string = &vm_symbol_bodies[0];
for (int index = (int)FIRST_SID; index < (int)SID_LIMIT; index++) {
- Symbol* sym = SymbolTable::new_permanent_symbol(string, CHECK);
+ Symbol* sym = SymbolTable::new_permanent_symbol(string);
_symbols[index] = sym;
string += strlen(string); // skip string body
string += 1; // skip trailing null
@@ -141,7 +141,7 @@
// Spot-check correspondence between strings, symbols, and enums:
assert(_symbols[NO_SID] == NULL, "must be");
const char* str = "java/lang/Object";
- TempNewSymbol jlo = SymbolTable::new_permanent_symbol(str, CHECK);
+ TempNewSymbol jlo = SymbolTable::new_permanent_symbol(str);
assert(strncmp(str, (char*)jlo->base(), jlo->utf8_length()) == 0, "");
assert(jlo == java_lang_Object(), "");
SID sid = VM_SYMBOL_ENUM_NAME(java_lang_Object);
@@ -160,7 +160,7 @@
// The string "format" happens (at the moment) not to be a vmSymbol,
// though it is a method name in java.lang.String.
str = "format";
- TempNewSymbol fmt = SymbolTable::new_permanent_symbol(str, CHECK);
+ TempNewSymbol fmt = SymbolTable::new_permanent_symbol(str);
sid = find_sid(fmt);
assert(sid == NO_SID, "symbol index works (negative test)");
}
--- a/src/hotspot/share/code/compiledMethod.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/code/compiledMethod.cpp Wed May 15 13:54:43 2019 +0530
@@ -468,39 +468,6 @@
return ic->set_to_clean();
}
-// static_stub_Relocations may have dangling references to
-// nmethods so trim them out here. Otherwise it looks like
-// compiled code is maintaining a link to dead metadata.
-void CompiledMethod::clean_ic_stubs() {
-#ifdef ASSERT
- address low_boundary = oops_reloc_begin();
- RelocIterator iter(this, low_boundary);
- while (iter.next()) {
- address static_call_addr = NULL;
- if (iter.type() == relocInfo::opt_virtual_call_type) {
- CompiledIC* cic = CompiledIC_at(&iter);
- if (!cic->is_call_to_interpreted()) {
- static_call_addr = iter.addr();
- }
- } else if (iter.type() == relocInfo::static_call_type) {
- CompiledStaticCall* csc = compiledStaticCall_at(iter.reloc());
- if (!csc->is_call_to_interpreted()) {
- static_call_addr = iter.addr();
- }
- }
- if (static_call_addr != NULL) {
- RelocIterator sciter(this, low_boundary);
- while (sciter.next()) {
- if (sciter.type() == relocInfo::static_stub_type &&
- sciter.static_stub_reloc()->static_call() == static_call_addr) {
- sciter.static_stub_reloc()->clear_inline_cache();
- }
- }
- }
- }
-#endif
-}
-
// Clean references to unloaded nmethods at addr from this one, which is not unloaded.
template <class CompiledICorStaticCall>
static bool clean_if_nmethod_is_unloaded(CompiledICorStaticCall *ic, address addr, CompiledMethod* from,
@@ -549,9 +516,6 @@
return false;
}
- // All static stubs need to be cleaned.
- clean_ic_stubs();
-
#ifdef ASSERT
// Check that the metadata embedded in the nmethod is alive
CheckClass check_class;
@@ -581,6 +545,7 @@
// Find all calls in an nmethod and clear the ones that point to non-entrant,
// zombie and unloaded nmethods.
RelocIterator iter(this, oops_reloc_begin());
+ bool is_in_static_stub = false;
while(iter.next()) {
switch (iter.type()) {
@@ -611,6 +576,45 @@
}
break;
+ case relocInfo::static_stub_type: {
+ is_in_static_stub = true;
+ break;
+ }
+
+ case relocInfo::metadata_type: {
+ // Only the metadata relocations contained in static/opt virtual call stubs
+ // contains the Method* passed to c2i adapters. It is the only metadata
+ // relocation that needs to be walked, as it is the one metadata relocation
+ // that violates the invariant that all metadata relocations have an oop
+ // in the compiled method (due to deferred resolution and code patching).
+
+ // This causes dead metadata to remain in compiled methods that are not
+ // unloading. Unless these slippery metadata relocations of the static
+ // stubs are at least cleared, subsequent class redefinition operations
+ // will access potentially free memory, and JavaThread execution
+ // concurrent to class unloading may call c2i adapters with dead methods.
+ if (!is_in_static_stub) {
+ // The first metadata relocation after a static stub relocation is the
+ // metadata relocation of the static stub used to pass the Method* to
+ // c2i adapters.
+ continue;
+ }
+ is_in_static_stub = false;
+ metadata_Relocation* r = iter.metadata_reloc();
+ Metadata* md = r->metadata_value();
+ if (md != NULL && md->is_method()) {
+ Method* method = static_cast<Method*>(md);
+ if (!method->method_holder()->is_loader_alive()) {
+ Atomic::store((Method*)NULL, r->metadata_addr());
+
+ if (!r->metadata_is_immediate()) {
+ r->fix_metadata_relocation();
+ }
+ }
+ }
+ break;
+ }
+
default:
break;
}
--- a/src/hotspot/share/code/compiledMethod.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/code/compiledMethod.hpp Wed May 15 13:54:43 2019 +0530
@@ -395,8 +395,6 @@
private:
bool static clean_ic_if_metadata_is_dead(CompiledIC *ic);
- void clean_ic_stubs();
-
public:
// GC unloading support
// Cleans unloaded klasses and unloaded nmethods in inline caches
--- a/src/hotspot/share/code/nmethod.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/code/nmethod.cpp Wed May 15 13:54:43 2019 +0530
@@ -1555,7 +1555,7 @@
// Visit all immediate references that are embedded in the instruction stream.
RelocIterator iter(this, oops_reloc_begin());
while (iter.next()) {
- if (iter.type() == relocInfo::metadata_type ) {
+ if (iter.type() == relocInfo::metadata_type) {
metadata_Relocation* r = iter.metadata_reloc();
// In this metadata, we must only follow those metadatas directly embedded in
// the code. Other metadatas (oop_index>0) are seen as part of
--- a/src/hotspot/share/compiler/compilerOracle.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/compiler/compilerOracle.cpp Wed May 15 13:54:43 2019 +0530
@@ -829,8 +829,8 @@
}
EXCEPTION_MARK;
- Symbol* c_name = SymbolTable::new_symbol(className, CHECK);
- Symbol* m_name = SymbolTable::new_symbol(methodName, CHECK);
+ Symbol* c_name = SymbolTable::new_symbol(className);
+ Symbol* m_name = SymbolTable::new_symbol(methodName);
Symbol* signature = NULL;
BasicMatcher* bm = new BasicMatcher();
--- a/src/hotspot/share/compiler/methodMatcher.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/compiler/methodMatcher.cpp Wed May 15 13:54:43 2019 +0530
@@ -300,10 +300,10 @@
}
line += bytes_read;
}
- signature = SymbolTable::new_symbol(sig, CHECK);
+ signature = SymbolTable::new_symbol(sig);
}
- Symbol* c_name = SymbolTable::new_symbol(class_name, CHECK);
- Symbol* m_name = SymbolTable::new_symbol(method_name, CHECK);
+ Symbol* c_name = SymbolTable::new_symbol(class_name);
+ Symbol* m_name = SymbolTable::new_symbol(method_name);
matcher->init(c_name, c_match, m_name, m_match, signature);
return;
--- a/src/hotspot/share/gc/g1/g1AllocRegion.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1AllocRegion.hpp Wed May 15 13:54:43 2019 +0530
@@ -27,7 +27,7 @@
#include "gc/g1/heapRegion.hpp"
#include "gc/g1/g1EvacStats.hpp"
-#include "gc/g1/g1InCSetState.hpp"
+#include "gc/g1/g1HeapRegionAttr.hpp"
class G1CollectedHeap;
@@ -249,14 +249,14 @@
class G1GCAllocRegion : public G1AllocRegion {
protected:
G1EvacStats* _stats;
- InCSetState::in_cset_state_t _purpose;
+ G1HeapRegionAttr::region_type_t _purpose;
virtual HeapRegion* allocate_new_region(size_t word_size, bool force);
virtual void retire_region(HeapRegion* alloc_region, size_t allocated_bytes);
virtual size_t retire(bool fill_up);
- G1GCAllocRegion(const char* name, bool bot_updates, G1EvacStats* stats, InCSetState::in_cset_state_t purpose)
+ G1GCAllocRegion(const char* name, bool bot_updates, G1EvacStats* stats, G1HeapRegionAttr::region_type_t purpose)
: G1AllocRegion(name, bot_updates), _stats(stats), _purpose(purpose) {
assert(stats != NULL, "Must pass non-NULL PLAB statistics");
}
@@ -265,13 +265,13 @@
class SurvivorGCAllocRegion : public G1GCAllocRegion {
public:
SurvivorGCAllocRegion(G1EvacStats* stats)
- : G1GCAllocRegion("Survivor GC Alloc Region", false /* bot_updates */, stats, InCSetState::Young) { }
+ : G1GCAllocRegion("Survivor GC Alloc Region", false /* bot_updates */, stats, G1HeapRegionAttr::Young) { }
};
class OldGCAllocRegion : public G1GCAllocRegion {
public:
OldGCAllocRegion(G1EvacStats* stats)
- : G1GCAllocRegion("Old GC Alloc Region", true /* bot_updates */, stats, InCSetState::Old) { }
+ : G1GCAllocRegion("Old GC Alloc Region", true /* bot_updates */, stats, G1HeapRegionAttr::Old) { }
// This specialization of release() makes sure that the last card that has
// been allocated into has been completely filled by a dummy object. This
--- a/src/hotspot/share/gc/g1/g1Allocator.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1Allocator.cpp Wed May 15 13:54:43 2019 +0530
@@ -39,8 +39,8 @@
_survivor_is_full(false),
_old_is_full(false),
_mutator_alloc_region(),
- _survivor_gc_alloc_region(heap->alloc_buffer_stats(InCSetState::Young)),
- _old_gc_alloc_region(heap->alloc_buffer_stats(InCSetState::Old)),
+ _survivor_gc_alloc_region(heap->alloc_buffer_stats(G1HeapRegionAttr::Young)),
+ _old_gc_alloc_region(heap->alloc_buffer_stats(G1HeapRegionAttr::Old)),
_retained_old_gc_alloc_region(NULL) {
}
@@ -161,7 +161,7 @@
}
-HeapWord* G1Allocator::par_allocate_during_gc(InCSetState dest,
+HeapWord* G1Allocator::par_allocate_during_gc(G1HeapRegionAttr dest,
size_t word_size) {
size_t temp = 0;
HeapWord* result = par_allocate_during_gc(dest, word_size, word_size, &temp);
@@ -171,14 +171,14 @@
return result;
}
-HeapWord* G1Allocator::par_allocate_during_gc(InCSetState dest,
+HeapWord* G1Allocator::par_allocate_during_gc(G1HeapRegionAttr dest,
size_t min_word_size,
size_t desired_word_size,
size_t* actual_word_size) {
- switch (dest.value()) {
- case InCSetState::Young:
+ switch (dest.type()) {
+ case G1HeapRegionAttr::Young:
return survivor_attempt_allocation(min_word_size, desired_word_size, actual_word_size);
- case InCSetState::Old:
+ case G1HeapRegionAttr::Old:
return old_attempt_allocation(min_word_size, desired_word_size, actual_word_size);
default:
ShouldNotReachHere();
@@ -246,22 +246,22 @@
G1PLABAllocator::G1PLABAllocator(G1Allocator* allocator) :
_g1h(G1CollectedHeap::heap()),
_allocator(allocator),
- _surviving_alloc_buffer(_g1h->desired_plab_sz(InCSetState::Young)),
- _tenured_alloc_buffer(_g1h->desired_plab_sz(InCSetState::Old)),
+ _surviving_alloc_buffer(_g1h->desired_plab_sz(G1HeapRegionAttr::Young)),
+ _tenured_alloc_buffer(_g1h->desired_plab_sz(G1HeapRegionAttr::Old)),
_survivor_alignment_bytes(calc_survivor_alignment_bytes()) {
- for (uint state = 0; state < InCSetState::Num; state++) {
+ for (uint state = 0; state < G1HeapRegionAttr::Num; state++) {
_direct_allocated[state] = 0;
_alloc_buffers[state] = NULL;
}
- _alloc_buffers[InCSetState::Young] = &_surviving_alloc_buffer;
- _alloc_buffers[InCSetState::Old] = &_tenured_alloc_buffer;
+ _alloc_buffers[G1HeapRegionAttr::Young] = &_surviving_alloc_buffer;
+ _alloc_buffers[G1HeapRegionAttr::Old] = &_tenured_alloc_buffer;
}
bool G1PLABAllocator::may_throw_away_buffer(size_t const allocation_word_sz, size_t const buffer_size) const {
return (allocation_word_sz * 100 < buffer_size * ParallelGCBufferWastePct);
}
-HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(InCSetState dest,
+HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(G1HeapRegionAttr dest,
size_t word_sz,
bool* plab_refill_failed) {
size_t plab_word_size = _g1h->desired_plab_sz(dest);
@@ -300,17 +300,17 @@
// Try direct allocation.
HeapWord* result = _allocator->par_allocate_during_gc(dest, word_sz);
if (result != NULL) {
- _direct_allocated[dest.value()] += word_sz;
+ _direct_allocated[dest.type()] += word_sz;
}
return result;
}
-void G1PLABAllocator::undo_allocation(InCSetState dest, HeapWord* obj, size_t word_sz) {
+void G1PLABAllocator::undo_allocation(G1HeapRegionAttr dest, HeapWord* obj, size_t word_sz) {
alloc_buffer(dest)->undo_allocation(obj, word_sz);
}
void G1PLABAllocator::flush_and_retire_stats() {
- for (uint state = 0; state < InCSetState::Num; state++) {
+ for (uint state = 0; state < G1HeapRegionAttr::Num; state++) {
PLAB* const buf = _alloc_buffers[state];
if (buf != NULL) {
G1EvacStats* stats = _g1h->alloc_buffer_stats(state);
@@ -323,7 +323,7 @@
size_t G1PLABAllocator::waste() const {
size_t result = 0;
- for (uint state = 0; state < InCSetState::Num; state++) {
+ for (uint state = 0; state < G1HeapRegionAttr::Num; state++) {
PLAB * const buf = _alloc_buffers[state];
if (buf != NULL) {
result += buf->waste();
@@ -334,7 +334,7 @@
size_t G1PLABAllocator::undo_waste() const {
size_t result = 0;
- for (uint state = 0; state < InCSetState::Num; state++) {
+ for (uint state = 0; state < G1HeapRegionAttr::Num; state++) {
PLAB * const buf = _alloc_buffers[state];
if (buf != NULL) {
result += buf->undo_waste();
--- a/src/hotspot/share/gc/g1/g1Allocator.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1Allocator.hpp Wed May 15 13:54:43 2019 +0530
@@ -26,7 +26,7 @@
#define SHARE_GC_G1_G1ALLOCATOR_HPP
#include "gc/g1/g1AllocRegion.hpp"
-#include "gc/g1/g1InCSetState.hpp"
+#include "gc/g1/g1HeapRegionAttr.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/plab.hpp"
@@ -112,10 +112,10 @@
// allocation region, either by picking one or expanding the
// heap, and then allocate a block of the given size. The block
// may not be a humongous - it must fit into a single heap region.
- HeapWord* par_allocate_during_gc(InCSetState dest,
+ HeapWord* par_allocate_during_gc(G1HeapRegionAttr dest,
size_t word_size);
- HeapWord* par_allocate_during_gc(InCSetState dest,
+ HeapWord* par_allocate_during_gc(G1HeapRegionAttr dest,
size_t min_word_size,
size_t desired_word_size,
size_t* actual_word_size);
@@ -132,7 +132,7 @@
PLAB _surviving_alloc_buffer;
PLAB _tenured_alloc_buffer;
- PLAB* _alloc_buffers[InCSetState::Num];
+ PLAB* _alloc_buffers[G1HeapRegionAttr::Num];
// The survivor alignment in effect in bytes.
// == 0 : don't align survivors
@@ -142,10 +142,10 @@
const uint _survivor_alignment_bytes;
// Number of words allocated directly (not counting PLAB allocation).
- size_t _direct_allocated[InCSetState::Num];
+ size_t _direct_allocated[G1HeapRegionAttr::Num];
void flush_and_retire_stats();
- inline PLAB* alloc_buffer(InCSetState dest);
+ inline PLAB* alloc_buffer(G1HeapRegionAttr dest);
// Calculate the survivor space object alignment in bytes. Returns that or 0 if
// there are no restrictions on survivor alignment.
@@ -162,20 +162,20 @@
// allocating a new PLAB. Returns the address of the allocated memory, NULL if
// not successful. Plab_refill_failed indicates whether an attempt to refill the
// PLAB failed or not.
- HeapWord* allocate_direct_or_new_plab(InCSetState dest,
+ HeapWord* allocate_direct_or_new_plab(G1HeapRegionAttr dest,
size_t word_sz,
bool* plab_refill_failed);
// Allocate word_sz words in the PLAB of dest. Returns the address of the
// allocated memory, NULL if not successful.
- inline HeapWord* plab_allocate(InCSetState dest,
+ inline HeapWord* plab_allocate(G1HeapRegionAttr dest,
size_t word_sz);
- inline HeapWord* allocate(InCSetState dest,
+ inline HeapWord* allocate(G1HeapRegionAttr dest,
size_t word_sz,
bool* refill_failed);
- void undo_allocation(InCSetState dest, HeapWord* obj, size_t word_sz);
+ void undo_allocation(G1HeapRegionAttr dest, HeapWord* obj, size_t word_sz);
};
// G1ArchiveRegionMap is a boolean array used to mark G1 regions as
--- a/src/hotspot/share/gc/g1/g1Allocator.inline.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1Allocator.inline.hpp Wed May 15 13:54:43 2019 +0530
@@ -63,15 +63,15 @@
return mutator_alloc_region()->attempt_allocation_force(word_size);
}
-inline PLAB* G1PLABAllocator::alloc_buffer(InCSetState dest) {
+inline PLAB* G1PLABAllocator::alloc_buffer(G1HeapRegionAttr dest) {
assert(dest.is_valid(),
- "Allocation buffer index out of bounds: " CSETSTATE_FORMAT, dest.value());
- assert(_alloc_buffers[dest.value()] != NULL,
- "Allocation buffer is NULL: " CSETSTATE_FORMAT, dest.value());
- return _alloc_buffers[dest.value()];
+ "Allocation buffer index out of bounds: %s", dest.get_type_str());
+ assert(_alloc_buffers[dest.type()] != NULL,
+ "Allocation buffer is NULL: %s", dest.get_type_str());
+ return _alloc_buffers[dest.type()];
}
-inline HeapWord* G1PLABAllocator::plab_allocate(InCSetState dest,
+inline HeapWord* G1PLABAllocator::plab_allocate(G1HeapRegionAttr dest,
size_t word_sz) {
PLAB* buffer = alloc_buffer(dest);
if (_survivor_alignment_bytes == 0 || !dest.is_young()) {
@@ -81,7 +81,7 @@
}
}
-inline HeapWord* G1PLABAllocator::allocate(InCSetState dest,
+inline HeapWord* G1PLABAllocator::allocate(G1HeapRegionAttr dest,
size_t word_sz,
bool* refill_failed) {
HeapWord* const obj = plab_allocate(dest, word_sz);
--- a/src/hotspot/share/gc/g1/g1BiasedArray.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1BiasedArray.hpp Wed May 15 13:54:43 2019 +0530
@@ -128,6 +128,11 @@
return biased_base()[biased_index];
}
+ T* get_ref_by_index(uintptr_t index) const {
+ verify_index(index);
+ return &this->base()[index];
+ }
+
// Return the index of the element of the given array that covers the given
// word in the heap.
idx_t get_index_by_address(HeapWord* value) const {
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Wed May 15 13:54:43 2019 +0530
@@ -1536,7 +1536,7 @@
_ref_processor_cm(NULL),
_is_alive_closure_cm(this),
_is_subject_to_discovery_cm(this),
- _in_cset_fast_test() {
+ _region_attr() {
_verifier = new G1HeapVerifier(this);
@@ -1772,7 +1772,7 @@
HeapWord* end = _hrm->reserved().end();
size_t granularity = HeapRegion::GrainBytes;
- _in_cset_fast_test.initialize(start, end, granularity);
+ _region_attr.initialize(start, end, granularity);
_humongous_reclaim_candidates.initialize(start, end, granularity);
}
@@ -2626,7 +2626,7 @@
G1EagerReclaimHumongousObjects && rem_set->is_empty();
}
-class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure {
+class RegisterRegionsWithRegionAttrTableClosure : public HeapRegionClosure {
private:
size_t _total_humongous;
size_t _candidate_humongous;
@@ -2690,24 +2690,26 @@
}
public:
- RegisterHumongousWithInCSetFastTestClosure()
+ RegisterRegionsWithRegionAttrTableClosure()
: _total_humongous(0),
_candidate_humongous(0),
_dcq(&G1BarrierSet::dirty_card_queue_set()) {
}
virtual bool do_heap_region(HeapRegion* r) {
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+
if (!r->is_starts_humongous()) {
+ g1h->register_region_with_region_attr(r);
return false;
}
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
bool is_candidate = humongous_region_is_candidate(g1h, r);
uint rindex = r->hrm_index();
g1h->set_humongous_reclaim_candidate(rindex, is_candidate);
if (is_candidate) {
_candidate_humongous++;
- g1h->register_humongous_region_with_cset(rindex);
+ g1h->register_humongous_region_with_region_attr(rindex);
// Is_candidate already filters out humongous object with large remembered sets.
// If we have a humongous object with a few remembered sets, we simply flush these
// remembered set entries into the DCQS. That will result in automatic
@@ -2743,8 +2745,14 @@
// collecting remembered set entries for humongous regions that were not
// reclaimed.
r->rem_set()->set_state_complete();
+#ifdef ASSERT
+ G1HeapRegionAttr region_attr = g1h->region_attr(oop(r->bottom()));
+ assert(region_attr.needs_remset_update(), "must be");
+#endif
}
assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty.");
+ } else {
+ g1h->register_region_with_region_attr(r);
}
_total_humongous++;
@@ -2757,21 +2765,15 @@
void flush_rem_set_entries() { _dcq.flush(); }
};
-void G1CollectedHeap::register_humongous_regions_with_cset() {
- if (!G1EagerReclaimHumongousObjects) {
- phase_times()->record_fast_reclaim_humongous_stats(0.0, 0, 0);
- return;
- }
- double time = os::elapsed_counter();
-
- // Collect reclaim candidate information and register candidates with cset.
- RegisterHumongousWithInCSetFastTestClosure cl;
+void G1CollectedHeap::register_regions_with_region_attr() {
+ Ticks start = Ticks::now();
+
+ RegisterRegionsWithRegionAttrTableClosure cl;
heap_region_iterate(&cl);
- time = ((double)(os::elapsed_counter() - time) / os::elapsed_frequency()) * 1000.0;
- phase_times()->record_fast_reclaim_humongous_stats(time,
- cl.total_humongous(),
- cl.candidate_humongous());
+ phase_times()->record_register_regions((Ticks::now() - start).seconds() * 1000.0,
+ cl.total_humongous(),
+ cl.candidate_humongous());
_has_humongous_reclaim_candidates = cl.candidate_humongous() > 0;
// Finally flush all remembered set entries to re-check into the global DCQS.
@@ -2861,7 +2863,7 @@
collection_set()->start_incremental_building();
- clear_cset_fast_test();
+ clear_region_attr();
guarantee(_eden.length() == 0, "eden should have been cleared");
policy()->transfer_survivors_to_cset(survivor());
@@ -3302,17 +3304,17 @@
oop obj = *p;
assert(obj != NULL, "the caller should have filtered out NULL values");
- const InCSetState cset_state =_g1h->in_cset_state(obj);
- if (!cset_state.is_in_cset_or_humongous()) {
+ const G1HeapRegionAttr region_attr =_g1h->region_attr(obj);
+ if (!region_attr.is_in_cset_or_humongous()) {
return;
}
- if (cset_state.is_in_cset()) {
+ if (region_attr.is_in_cset()) {
assert( obj->is_forwarded(), "invariant" );
*p = obj->forwardee();
} else {
assert(!obj->is_forwarded(), "invariant" );
- assert(cset_state.is_humongous(),
- "Only allowed InCSet state is IsHumongous, but is %d", cset_state.value());
+ assert(region_attr.is_humongous(),
+ "Only allowed G1HeapRegionAttr state is IsHumongous, but is %d", region_attr.type());
_g1h->set_humongous_is_live(obj);
}
}
@@ -3572,10 +3574,10 @@
// Initialize the GC alloc regions.
_allocator->init_gc_alloc_regions(evacuation_info);
- register_humongous_regions_with_cset();
+ register_regions_with_region_attr();
assert(_verifier->check_cset_fast_test(), "Inconsistency in the InCSetState table.");
- rem_set()->prepare_for_oops_into_collection_set_do();
+ rem_set()->prepare_for_scan_rem_set();
_preserved_marks_set.assert_empty();
#if COMPILER2_OR_JVMCI
@@ -3788,7 +3790,7 @@
void G1CollectedHeap::post_evacuate_collection_set(G1EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* per_thread_states) {
// Also cleans the card table from temporary duplicate detection information used
// during UpdateRS/ScanRS.
- rem_set()->cleanup_after_oops_into_collection_set_do();
+ rem_set()->cleanup_after_scan_rem_set();
// Process any discovered reference objects - we have
// to do this _before_ we retire the GC alloc regions
@@ -3970,7 +3972,7 @@
G1CollectedHeap* g1h = G1CollectedHeap::heap();
assert(r->in_collection_set(), "Region %u should be in collection set.", r->hrm_index());
- g1h->clear_in_cset(r);
+ g1h->clear_region_attr(r);
if (r->is_young()) {
assert(r->young_index_in_cset() != -1 && (uint)r->young_index_in_cset() < g1h->collection_set()->young_region_length(),
@@ -4031,7 +4033,7 @@
G1Policy* policy = g1h->policy();
policy->add_bytes_allocated_in_old_since_last_gc(_bytes_allocated_in_old_since_last_gc);
- g1h->alloc_buffer_stats(InCSetState::Old)->add_failure_used_and_waste(_failure_used_words, _failure_waste_words);
+ g1h->alloc_buffer_stats(G1HeapRegionAttr::Old)->add_failure_used_and_waste(_failure_used_words, _failure_waste_words);
}
};
@@ -4365,7 +4367,7 @@
public:
virtual bool do_heap_region(HeapRegion* r) {
assert(r->in_collection_set(), "Region %u must have been in collection set", r->hrm_index());
- G1CollectedHeap::heap()->clear_in_cset(r);
+ G1CollectedHeap::heap()->clear_region_attr(r);
r->set_young_index_in_cset(-1);
return false;
}
@@ -4582,7 +4584,7 @@
// Methods for the GC alloc regions
-bool G1CollectedHeap::has_more_regions(InCSetState dest) {
+bool G1CollectedHeap::has_more_regions(G1HeapRegionAttr dest) {
if (dest.is_old()) {
return true;
} else {
@@ -4590,7 +4592,7 @@
}
}
-HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, InCSetState dest) {
+HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegionAttr dest) {
assert(FreeList_lock->owned_by_self(), "pre-condition");
if (!has_more_regions(dest)) {
@@ -4618,6 +4620,7 @@
_verifier->check_bitmaps("Old Region Allocation", new_alloc_region);
}
_policy->remset_tracker()->update_at_allocate(new_alloc_region);
+ register_region_with_region_attr(new_alloc_region);
_hr_printer.alloc(new_alloc_region);
return new_alloc_region;
}
@@ -4626,12 +4629,12 @@
void G1CollectedHeap::retire_gc_alloc_region(HeapRegion* alloc_region,
size_t allocated_bytes,
- InCSetState dest) {
+ G1HeapRegionAttr dest) {
policy()->record_bytes_copied_during_gc(allocated_bytes);
if (dest.is_old()) {
old_set_add(alloc_region);
} else {
- assert(dest.is_young(), "Retiring alloc region should be young(%d)", dest.value());
+ assert(dest.is_young(), "Retiring alloc region should be young (%d)", dest.type());
_survivor.add_used_bytes(allocated_bytes);
}
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Wed May 15 13:54:43 2019 +0530
@@ -40,7 +40,7 @@
#include "gc/g1/g1HeapTransition.hpp"
#include "gc/g1/g1HeapVerifier.hpp"
#include "gc/g1/g1HRPrinter.hpp"
-#include "gc/g1/g1InCSetState.hpp"
+#include "gc/g1/g1HeapRegionAttr.hpp"
#include "gc/g1/g1MonitoringSupport.hpp"
#include "gc/g1/g1SurvivorRegions.hpp"
#include "gc/g1/g1YCTypes.hpp"
@@ -464,10 +464,10 @@
size_t allocated_bytes);
// For GC alloc regions.
- bool has_more_regions(InCSetState dest);
- HeapRegion* new_gc_alloc_region(size_t word_size, InCSetState dest);
+ bool has_more_regions(G1HeapRegionAttr dest);
+ HeapRegion* new_gc_alloc_region(size_t word_size, G1HeapRegionAttr dest);
void retire_gc_alloc_region(HeapRegion* alloc_region,
- size_t allocated_bytes, InCSetState dest);
+ size_t allocated_bytes, G1HeapRegionAttr dest);
// - if explicit_gc is true, the GC is for a System.gc() etc,
// otherwise it's for a failed allocation.
@@ -551,10 +551,10 @@
bool expand(size_t expand_bytes, WorkGang* pretouch_workers = NULL, double* expand_time_ms = NULL);
// Returns the PLAB statistics for a given destination.
- inline G1EvacStats* alloc_buffer_stats(InCSetState dest);
+ inline G1EvacStats* alloc_buffer_stats(G1HeapRegionAttr dest);
// Determines PLAB size for a given destination.
- inline size_t desired_plab_sz(InCSetState dest);
+ inline size_t desired_plab_sz(G1HeapRegionAttr dest);
// Do anything common to GC's.
void gc_prologue(bool full);
@@ -573,27 +573,24 @@
inline void set_humongous_is_live(oop obj);
// Register the given region to be part of the collection set.
- inline void register_humongous_region_with_cset(uint index);
- // Register regions with humongous objects (actually on the start region) in
- // the in_cset_fast_test table.
- void register_humongous_regions_with_cset();
+ inline void register_humongous_region_with_region_attr(uint index);
+ // Update region attributes table with information about all regions.
+ void register_regions_with_region_attr();
// We register a region with the fast "in collection set" test. We
// simply set to true the array slot corresponding to this region.
- void register_young_region_with_cset(HeapRegion* r) {
- _in_cset_fast_test.set_in_young(r->hrm_index());
- }
- void register_old_region_with_cset(HeapRegion* r) {
- _in_cset_fast_test.set_in_old(r->hrm_index());
+ void register_young_region_with_region_attr(HeapRegion* r) {
+ _region_attr.set_in_young(r->hrm_index());
}
- void register_optional_region_with_cset(HeapRegion* r) {
- _in_cset_fast_test.set_optional(r->hrm_index());
- }
- void clear_in_cset(const HeapRegion* hr) {
- _in_cset_fast_test.clear(hr);
+ inline void register_region_with_region_attr(HeapRegion* r);
+ inline void register_old_region_with_region_attr(HeapRegion* r);
+ inline void register_optional_region_with_region_attr(HeapRegion* r);
+
+ void clear_region_attr(const HeapRegion* hr) {
+ _region_attr.clear(hr);
}
- void clear_cset_fast_test() {
- _in_cset_fast_test.clear();
+ void clear_region_attr() {
+ _region_attr.clear();
}
bool is_user_requested_concurrent_full_gc(GCCause::Cause cause);
@@ -1110,11 +1107,11 @@
// This array is used for a quick test on whether a reference points into
// the collection set or not. Each of the array's elements denotes whether the
// corresponding region is in the collection set or not.
- G1InCSetStateFastTestBiasedMappedArray _in_cset_fast_test;
+ G1HeapRegionAttrBiasedMappedArray _region_attr;
public:
- inline InCSetState in_cset_state(const oop obj);
+ inline G1HeapRegionAttr region_attr(const oop obj);
// Return "TRUE" iff the given object address is in the reserved
// region of g1.
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp Wed May 15 13:54:43 2019 +0530
@@ -30,6 +30,7 @@
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1Policy.hpp"
#include "gc/g1/heapRegionManager.inline.hpp"
+#include "gc/g1/heapRegionRemSet.hpp"
#include "gc/g1/heapRegionSet.inline.hpp"
#include "gc/shared/taskqueue.inline.hpp"
#include "runtime/orderAccess.hpp"
@@ -38,11 +39,11 @@
return _policy->phase_times();
}
-G1EvacStats* G1CollectedHeap::alloc_buffer_stats(InCSetState dest) {
- switch (dest.value()) {
- case InCSetState::Young:
+G1EvacStats* G1CollectedHeap::alloc_buffer_stats(G1HeapRegionAttr dest) {
+ switch (dest.type()) {
+ case G1HeapRegionAttr::Young:
return &_survivor_evac_stats;
- case InCSetState::Old:
+ case G1HeapRegionAttr::Old:
return &_old_evac_stats;
default:
ShouldNotReachHere();
@@ -50,7 +51,7 @@
}
}
-size_t G1CollectedHeap::desired_plab_sz(InCSetState dest) {
+size_t G1CollectedHeap::desired_plab_sz(G1HeapRegionAttr dest) {
size_t gclab_word_size = alloc_buffer_stats(dest)->desired_plab_sz(workers()->active_workers());
// Prevent humongous PLAB sizes for two reasons:
// * PLABs are allocated using a similar paths as oops, but should
@@ -150,23 +151,35 @@
}
inline bool G1CollectedHeap::is_in_cset(HeapWord* addr) {
- return _in_cset_fast_test.is_in_cset(addr);
+ return _region_attr.is_in_cset(addr);
}
bool G1CollectedHeap::is_in_cset(const HeapRegion* hr) {
- return _in_cset_fast_test.is_in_cset(hr);
+ return _region_attr.is_in_cset(hr);
}
bool G1CollectedHeap::is_in_cset_or_humongous(const oop obj) {
- return _in_cset_fast_test.is_in_cset_or_humongous((HeapWord*)obj);
+ return _region_attr.is_in_cset_or_humongous((HeapWord*)obj);
+}
+
+G1HeapRegionAttr G1CollectedHeap::region_attr(const oop obj) {
+ return _region_attr.at((HeapWord*)obj);
+}
+
+void G1CollectedHeap::register_humongous_region_with_region_attr(uint index) {
+ _region_attr.set_humongous(index, region_at(index)->rem_set()->is_tracked());
}
-InCSetState G1CollectedHeap::in_cset_state(const oop obj) {
- return _in_cset_fast_test.at((HeapWord*)obj);
+void G1CollectedHeap::register_region_with_region_attr(HeapRegion* r) {
+ _region_attr.set_has_remset(r->hrm_index(), r->rem_set()->is_tracked());
}
-void G1CollectedHeap::register_humongous_region_with_cset(uint index) {
- _in_cset_fast_test.set_humongous(index);
+void G1CollectedHeap::register_old_region_with_region_attr(HeapRegion* r) {
+ _region_attr.set_in_old(r->hrm_index(), r->rem_set()->is_tracked());
+}
+
+void G1CollectedHeap::register_optional_region_with_region_attr(HeapRegion* r) {
+ _region_attr.set_optional(r->hrm_index(), r->rem_set()->is_tracked());
}
#ifndef PRODUCT
@@ -294,7 +307,7 @@
// thread (i.e. within the VM thread).
if (is_humongous_reclaim_candidate(region)) {
set_humongous_reclaim_candidate(region, false);
- _in_cset_fast_test.clear_humongous(region);
+ _region_attr.clear_humongous(region);
}
}
--- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp Wed May 15 13:54:43 2019 +0530
@@ -121,7 +121,7 @@
assert(hr->is_old(), "the region should be old");
assert(!hr->in_collection_set(), "should not already be in the collection set");
- _g1h->register_old_region_with_cset(hr);
+ _g1h->register_old_region_with_region_attr(hr);
_collection_set_regions[_collection_set_cur_length++] = hr->hrm_index();
assert(_collection_set_cur_length <= _collection_set_max_length, "Collection set now larger than maximum size.");
@@ -137,7 +137,7 @@
assert(hr->is_old(), "the region should be old");
assert(!hr->in_collection_set(), "should not already be in the CSet");
- _g1h->register_optional_region_with_cset(hr);
+ _g1h->register_optional_region_with_region_attr(hr);
hr->set_index_in_opt_cset(_num_optional_regions++);
}
@@ -316,7 +316,7 @@
}
assert(!hr->in_collection_set(), "invariant");
- _g1h->register_young_region_with_cset(hr);
+ _g1h->register_young_region_with_region_attr(hr);
}
void G1CollectionSet::add_survivor_regions(HeapRegion* hr) {
@@ -492,7 +492,7 @@
HeapRegion* r = candidates()->at(candidate_idx + i);
// This potentially optional candidate region is going to be an actual collection
// set region. Clear cset marker.
- _g1h->clear_in_cset(r);
+ _g1h->clear_region_attr(r);
add_old_region(r);
}
candidates()->remove(num_old_candidate_regions);
@@ -526,7 +526,7 @@
for (uint i = 0; i < _num_optional_regions; i++) {
HeapRegion* r = candidates()->at(candidates()->cur_idx() + i);
pss->record_unused_optional_region(r);
- _g1h->clear_in_cset(r);
+ _g1h->clear_region_attr(r);
r->clear_index_in_opt_cset();
}
free_optional_regions();
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp Wed May 15 13:54:43 2019 +0530
@@ -170,7 +170,7 @@
_recorded_total_free_cset_time_ms = 0.0;
_recorded_serial_free_cset_time_ms = 0.0;
_cur_fast_reclaim_humongous_time_ms = 0.0;
- _cur_fast_reclaim_humongous_register_time_ms = 0.0;
+ _cur_region_register_time = 0.0;
_cur_fast_reclaim_humongous_total = 0;
_cur_fast_reclaim_humongous_candidates = 0;
_cur_fast_reclaim_humongous_reclaimed = 0;
@@ -364,7 +364,7 @@
const double sum_ms = _root_region_scan_wait_time_ms +
_recorded_young_cset_choice_time_ms +
_recorded_non_young_cset_choice_time_ms +
- _cur_fast_reclaim_humongous_register_time_ms +
+ _cur_region_register_time +
_recorded_clear_claimed_marks_time_ms;
info_time("Pre Evacuate Collection Set", sum_ms);
@@ -374,8 +374,8 @@
}
debug_time("Prepare TLABs", _cur_prepare_tlab_time_ms);
debug_time("Choose Collection Set", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms));
+ debug_time("Region Register", _cur_region_register_time);
if (G1EagerReclaimHumongousObjects) {
- debug_time("Humongous Register", _cur_fast_reclaim_humongous_register_time_ms);
trace_count("Humongous Total", _cur_fast_reclaim_humongous_total);
trace_count("Humongous Candidate", _cur_fast_reclaim_humongous_candidates);
}
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp Wed May 15 13:54:43 2019 +0530
@@ -176,8 +176,9 @@
double _recorded_serial_free_cset_time_ms;
+ double _cur_region_register_time;
+
double _cur_fast_reclaim_humongous_time_ms;
- double _cur_fast_reclaim_humongous_register_time_ms;
size_t _cur_fast_reclaim_humongous_total;
size_t _cur_fast_reclaim_humongous_candidates;
size_t _cur_fast_reclaim_humongous_reclaimed;
@@ -305,8 +306,8 @@
_recorded_serial_free_cset_time_ms = time_ms;
}
- void record_fast_reclaim_humongous_stats(double time_ms, size_t total, size_t candidates) {
- _cur_fast_reclaim_humongous_register_time_ms = time_ms;
+ void record_register_regions(double time_ms, size_t total, size_t candidates) {
+ _cur_region_register_time = time_ms;
_cur_fast_reclaim_humongous_total = total;
_cur_fast_reclaim_humongous_candidates = candidates;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp Wed May 15 13:54:43 2019 +0530
@@ -0,0 +1,164 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_GC_G1_G1HEAPREGIONATTR_HPP
+#define SHARE_GC_G1_G1HEAPREGIONATTR_HPP
+
+#include "gc/g1/g1BiasedArray.hpp"
+#include "gc/g1/heapRegion.hpp"
+
+// Per-region attributes often used during garbage collection to avoid costly
+// lookups for that information all over the place.
+struct G1HeapRegionAttr {
+public:
+ // We use different types to represent the state value depending on platform as
+ // some have issues loading parts of words.
+#ifdef SPARC
+ typedef int32_t region_type_t;
+ typedef uint32_t needs_remset_update_t;
+#else
+ typedef int8_t region_type_t;
+ typedef uint8_t needs_remset_update_t;
+#endif
+
+private:
+ needs_remset_update_t _needs_remset_update;
+ region_type_t _type;
+
+public:
+ // Selection of the values for the _type field were driven to micro-optimize the
+ // encoding and frequency of the checks.
+ // The most common check for a given reference is whether the region is in the
+ // collection set or not, and which generation this region is in.
+ // The selected encoding allows us to use a single check (> NotInCSet) for the
+ // former.
+ //
+ // The other values are used for objects requiring various special cases,
+ // for example eager reclamation of humongous objects or optional regions.
+ static const region_type_t Optional = -2; // The region is optional and NOT in the current collection set.
+ static const region_type_t Humongous = -1; // The region is a humongous candidate not in the current collection set.
+ static const region_type_t NotInCSet = 0; // The region is not in the collection set.
+ static const region_type_t Young = 1; // The region is in the collection set and a young region.
+ static const region_type_t Old = 2; // The region is in the collection set and an old region.
+ static const region_type_t Num = 3;
+
+ G1HeapRegionAttr(region_type_t type = NotInCSet, bool needs_remset_update = false) :
+ _needs_remset_update(needs_remset_update), _type(type) {
+
+ assert(is_valid(), "Invalid type %d", _type);
+ }
+
+ region_type_t type() const { return _type; }
+
+ const char* get_type_str() const {
+ switch (type()) {
+ case Optional: return "Optional";
+ case Humongous: return "Humongous";
+ case NotInCSet: return "NotInCSet";
+ case Young: return "Young";
+ case Old: return "Old";
+ default: ShouldNotReachHere(); return "";
+ }
+ }
+
+ bool needs_remset_update() const { return _needs_remset_update != 0; }
+
+ void set_old() { _type = Old; }
+ void clear_humongous() {
+ assert(is_humongous() || !is_in_cset(), "must be");
+ _type = NotInCSet;
+ }
+ void set_has_remset(bool value) { _needs_remset_update = value ? 1 : 0; }
+
+ bool is_in_cset_or_humongous() const { return is_in_cset() || is_humongous(); }
+ bool is_in_cset() const { return type() > NotInCSet; }
+
+ bool is_humongous() const { return type() == Humongous; }
+ bool is_young() const { return type() == Young; }
+ bool is_old() const { return type() == Old; }
+ bool is_optional() const { return type() == Optional; }
+
+#ifdef ASSERT
+ bool is_default() const { return type() == NotInCSet; }
+ bool is_valid() const { return (type() >= Optional && type() < Num); }
+ bool is_valid_gen() const { return (type() >= Young && type() <= Old); }
+#endif
+};
+
+// Table for all regions in the heap for above.
+//
+// We use this to speed up reference processing during young collection and
+// quickly reclaim humongous objects. For the latter, at the start of GC, by adding
+// it as a humongous region we enable special handling for that region. During the
+// reference iteration closures, when we see a humongous region, we then simply mark
+// it as referenced, i.e. live, and remove it from this table to prevent further
+// processing on it.
+//
+// This means that this does NOT completely correspond to the information stored
+// in a HeapRegion, but only to what is interesting for the current young collection.
+class G1HeapRegionAttrBiasedMappedArray : public G1BiasedMappedArray<G1HeapRegionAttr> {
+ protected:
+ G1HeapRegionAttr default_value() const { return G1HeapRegionAttr(G1HeapRegionAttr::NotInCSet); }
+ public:
+ void set_optional(uintptr_t index, bool needs_remset_update) {
+ assert(get_by_index(index).is_default(),
+ "Region attributes at index " INTPTR_FORMAT " should be default but is %s", index, get_by_index(index).get_type_str());
+ set_by_index(index, G1HeapRegionAttr(G1HeapRegionAttr::Optional, needs_remset_update));
+ }
+
+ void set_humongous(uintptr_t index, bool needs_remset_update) {
+ assert(get_by_index(index).is_default(),
+ "Region attributes at index " INTPTR_FORMAT " should be default but is %s", index, get_by_index(index).get_type_str());
+ set_by_index(index, G1HeapRegionAttr(G1HeapRegionAttr::Humongous, needs_remset_update));
+ }
+
+ void clear_humongous(uintptr_t index) {
+ get_ref_by_index(index)->clear_humongous();
+ }
+
+ void set_has_remset(uintptr_t index, bool needs_remset_update) {
+ get_ref_by_index(index)->set_has_remset(needs_remset_update);
+ }
+
+ void set_in_young(uintptr_t index) {
+ assert(get_by_index(index).is_default(),
+ "Region attributes at index " INTPTR_FORMAT " should be default but is %s", index, get_by_index(index).get_type_str());
+ set_by_index(index, G1HeapRegionAttr(G1HeapRegionAttr::Young, true));
+ }
+
+ void set_in_old(uintptr_t index, bool needs_remset_update) {
+ assert(get_by_index(index).is_default(),
+ "Region attributes at index " INTPTR_FORMAT " should be default but is %s", index, get_by_index(index).get_type_str());
+ set_by_index(index, G1HeapRegionAttr(G1HeapRegionAttr::Old, needs_remset_update));
+ }
+
+ bool is_in_cset_or_humongous(HeapWord* addr) const { return at(addr).is_in_cset_or_humongous(); }
+ bool is_in_cset(HeapWord* addr) const { return at(addr).is_in_cset(); }
+ bool is_in_cset(const HeapRegion* hr) const { return get_by_index(hr->hrm_index()).is_in_cset(); }
+ G1HeapRegionAttr at(HeapWord* addr) const { return get_by_address(addr); }
+ void clear() { G1BiasedMappedArray<G1HeapRegionAttr>::clear(); }
+ void clear(const HeapRegion* hr) { return set_by_index(hr->hrm_index(), G1HeapRegionAttr(G1HeapRegionAttr::NotInCSet)); }
+};
+
+#endif // SHARE_GC_G1_G1HEAPREGIONATTR_HPP
--- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp Wed May 15 13:54:43 2019 +0530
@@ -790,50 +790,50 @@
virtual bool do_heap_region(HeapRegion* hr) {
uint i = hr->hrm_index();
- InCSetState cset_state = (InCSetState) G1CollectedHeap::heap()->_in_cset_fast_test.get_by_index(i);
+ G1HeapRegionAttr region_attr = (G1HeapRegionAttr) G1CollectedHeap::heap()->_region_attr.get_by_index(i);
if (hr->is_humongous()) {
if (hr->in_collection_set()) {
log_error(gc, verify)("## humongous region %u in CSet", i);
_failures = true;
return true;
}
- if (cset_state.is_in_cset()) {
- log_error(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for humongous region %u", cset_state.value(), i);
+ if (region_attr.is_in_cset()) {
+ log_error(gc, verify)("## inconsistent region attr type %s for humongous region %u", region_attr.get_type_str(), i);
_failures = true;
return true;
}
- if (hr->is_continues_humongous() && cset_state.is_humongous()) {
- log_error(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for continues humongous region %u", cset_state.value(), i);
+ if (hr->is_continues_humongous() && region_attr.is_humongous()) {
+ log_error(gc, verify)("## inconsistent region attr type %s for continues humongous region %u", region_attr.get_type_str(), i);
_failures = true;
return true;
}
} else {
- if (cset_state.is_humongous()) {
- log_error(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for non-humongous region %u", cset_state.value(), i);
+ if (region_attr.is_humongous()) {
+ log_error(gc, verify)("## inconsistent region attr type %s for non-humongous region %u", region_attr.get_type_str(), i);
_failures = true;
return true;
}
- if (hr->in_collection_set() != cset_state.is_in_cset()) {
- log_error(gc, verify)("## in CSet %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
- hr->in_collection_set(), cset_state.value(), i);
+ if (hr->in_collection_set() != region_attr.is_in_cset()) {
+ log_error(gc, verify)("## in CSet %d / region attr type %s inconsistency for region %u",
+ hr->in_collection_set(), region_attr.get_type_str(), i);
_failures = true;
return true;
}
- if (cset_state.is_in_cset()) {
+ if (region_attr.is_in_cset()) {
if (hr->is_archive()) {
log_error(gc, verify)("## is_archive in collection set for region %u", i);
_failures = true;
return true;
}
- if (hr->is_young() != (cset_state.is_young())) {
- log_error(gc, verify)("## is_young %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
- hr->is_young(), cset_state.value(), i);
+ if (hr->is_young() != (region_attr.is_young())) {
+ log_error(gc, verify)("## is_young %d / region attr type %s inconsistency for region %u",
+ hr->is_young(), region_attr.get_type_str(), i);
_failures = true;
return true;
}
- if (hr->is_old() != (cset_state.is_old())) {
- log_error(gc, verify)("## is_old %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
- hr->is_old(), cset_state.value(), i);
+ if (hr->is_old() != (region_attr.is_old())) {
+ log_error(gc, verify)("## is_old %d / region attr type %s inconsistency for region %u",
+ hr->is_old(), region_attr.get_type_str(), i);
_failures = true;
return true;
}
--- a/src/hotspot/share/gc/g1/g1InCSetState.hpp Tue May 14 11:23:08 2019 +0530
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_GC_G1_G1INCSETSTATE_HPP
-#define SHARE_GC_G1_G1INCSETSTATE_HPP
-
-#include "gc/g1/g1BiasedArray.hpp"
-#include "gc/g1/heapRegion.hpp"
-
-// Per-region state during garbage collection.
-struct InCSetState {
- public:
- // We use different types to represent the state value. Particularly SPARC puts
- // values in structs from "left to right", i.e. MSB to LSB. This results in many
- // unnecessary shift operations when loading and storing values of this type.
- // This degrades performance significantly (>10%) on that platform.
- // Other tested ABIs do not seem to have this problem, and actually tend to
- // favor smaller types, so we use the smallest usable type there.
-#ifdef SPARC
- #define CSETSTATE_FORMAT INTPTR_FORMAT
- typedef intptr_t in_cset_state_t;
-#else
- #define CSETSTATE_FORMAT "%d"
- typedef int8_t in_cset_state_t;
-#endif
- private:
- in_cset_state_t _value;
- public:
- enum {
- // Selection of the values were driven to micro-optimize the encoding and
- // frequency of the checks.
- // The most common check is whether the region is in the collection set or not,
- // this encoding allows us to use an > 0 check.
- // The positive values are encoded in increasing generation order, which
- // makes getting the next generation fast by a simple increment. They are also
- // used to index into arrays.
- // The negative values are used for objects requiring various special cases,
- // for example eager reclamation of humongous objects or optional regions.
- Optional = -2, // The region is optional
- Humongous = -1, // The region is humongous
- NotInCSet = 0, // The region is not in the collection set.
- Young = 1, // The region is in the collection set and a young region.
- Old = 2, // The region is in the collection set and an old region.
- Num
- };
-
- InCSetState(in_cset_state_t value = NotInCSet) : _value(value) {
- assert(is_valid(), "Invalid state %d", _value);
- }
-
- in_cset_state_t value() const { return _value; }
-
- void set_old() { _value = Old; }
-
- bool is_in_cset_or_humongous() const { return is_in_cset() || is_humongous(); }
- bool is_in_cset() const { return _value > NotInCSet; }
-
- bool is_humongous() const { return _value == Humongous; }
- bool is_young() const { return _value == Young; }
- bool is_old() const { return _value == Old; }
- bool is_optional() const { return _value == Optional; }
-
-#ifdef ASSERT
- bool is_default() const { return _value == NotInCSet; }
- bool is_valid() const { return (_value >= Optional) && (_value < Num); }
- bool is_valid_gen() const { return (_value >= Young && _value <= Old); }
-#endif
-};
-
-// Instances of this class are used for quick tests on whether a reference points
-// into the collection set and into which generation or is a humongous object
-//
-// Each of the array's elements indicates whether the corresponding region is in
-// the collection set and if so in which generation, or a humongous region.
-//
-// We use this to speed up reference processing during young collection and
-// quickly reclaim humongous objects. For the latter, by making a humongous region
-// succeed this test, we sort-of add it to the collection set. During the reference
-// iteration closures, when we see a humongous region, we then simply mark it as
-// referenced, i.e. live.
-class G1InCSetStateFastTestBiasedMappedArray : public G1BiasedMappedArray<InCSetState> {
- protected:
- InCSetState default_value() const { return InCSetState::NotInCSet; }
- public:
- void set_optional(uintptr_t index) {
- assert(get_by_index(index).is_default(),
- "State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value());
- set_by_index(index, InCSetState::Optional);
- }
-
- void set_humongous(uintptr_t index) {
- assert(get_by_index(index).is_default(),
- "State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value());
- set_by_index(index, InCSetState::Humongous);
- }
-
- void clear_humongous(uintptr_t index) {
- set_by_index(index, InCSetState::NotInCSet);
- }
-
- void set_in_young(uintptr_t index) {
- assert(get_by_index(index).is_default(),
- "State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value());
- set_by_index(index, InCSetState::Young);
- }
-
- void set_in_old(uintptr_t index) {
- assert(get_by_index(index).is_default(),
- "State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value());
- set_by_index(index, InCSetState::Old);
- }
-
- bool is_in_cset_or_humongous(HeapWord* addr) const { return at(addr).is_in_cset_or_humongous(); }
- bool is_in_cset(HeapWord* addr) const { return at(addr).is_in_cset(); }
- bool is_in_cset(const HeapRegion* hr) const { return get_by_index(hr->hrm_index()).is_in_cset(); }
- InCSetState at(HeapWord* addr) const { return get_by_address(addr); }
- void clear() { G1BiasedMappedArray<InCSetState>::clear(); }
- void clear(const HeapRegion* hr) { return set_by_index(hr->hrm_index(), InCSetState::NotInCSet); }
-};
-
-#endif // SHARE_GC_G1_G1INCSETSTATE_HPP
--- a/src/hotspot/share/gc/g1/g1OopClosures.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1OopClosures.hpp Wed May 15 13:54:43 2019 +0530
@@ -25,7 +25,7 @@
#ifndef SHARE_GC_G1_G1OOPCLOSURES_HPP
#define SHARE_GC_G1_G1OOPCLOSURES_HPP
-#include "gc/g1/g1InCSetState.hpp"
+#include "gc/g1/g1HeapRegionAttr.hpp"
#include "memory/iterator.hpp"
#include "oops/markOop.hpp"
@@ -52,18 +52,18 @@
inline void prefetch_and_push(T* p, oop const obj);
template <class T>
- inline void handle_non_cset_obj_common(InCSetState const state, T* p, oop const obj);
+ inline void handle_non_cset_obj_common(G1HeapRegionAttr const region_attr, T* p, oop const obj);
public:
virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; }
inline void trim_queue_partially();
};
-// Used during the Update RS phase to refine remaining cards in the DCQ during garbage collection.
-class G1ScanObjsDuringUpdateRSClosure : public G1ScanClosureBase {
+// Used to scan cards from the DCQS or the remembered sets during garbage collection.
+class G1ScanCardClosure : public G1ScanClosureBase {
public:
- G1ScanObjsDuringUpdateRSClosure(G1CollectedHeap* g1h,
- G1ParScanThreadState* pss) :
+ G1ScanCardClosure(G1CollectedHeap* g1h,
+ G1ParScanThreadState* pss) :
G1ScanClosureBase(g1h, pss) { }
template <class T> void do_oop_work(T* p);
@@ -71,23 +71,11 @@
virtual void do_oop(oop* p) { do_oop_work(p); }
};
-// Used during the Scan RS phase to scan cards from the remembered set during garbage collection.
-class G1ScanObjsDuringScanRSClosure : public G1ScanClosureBase {
-public:
- G1ScanObjsDuringScanRSClosure(G1CollectedHeap* g1h,
- G1ParScanThreadState* par_scan_state):
- G1ScanClosureBase(g1h, par_scan_state) { }
-
- template <class T> void do_oop_work(T* p);
- virtual void do_oop(oop* p) { do_oop_work(p); }
- virtual void do_oop(narrowOop* p) { do_oop_work(p); }
-};
-
// Used during Optional RS scanning to make sure we trim the queues in a timely manner.
class G1ScanRSForOptionalClosure : public OopClosure {
- G1ScanObjsDuringScanRSClosure* _scan_cl;
+ G1ScanCardClosure* _scan_cl;
public:
- G1ScanRSForOptionalClosure(G1ScanObjsDuringScanRSClosure* cl) : _scan_cl(cl) { }
+ G1ScanRSForOptionalClosure(G1ScanCardClosure* cl) : _scan_cl(cl) { }
template <class T> void do_oop_work(T* p);
virtual void do_oop(oop* p) { do_oop_work(p); }
--- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp Wed May 15 13:54:43 2019 +0530
@@ -61,10 +61,10 @@
}
template <class T>
-inline void G1ScanClosureBase::handle_non_cset_obj_common(InCSetState const state, T* p, oop const obj) {
- if (state.is_humongous()) {
+inline void G1ScanClosureBase::handle_non_cset_obj_common(G1HeapRegionAttr const region_attr, T* p, oop const obj) {
+ if (region_attr.is_humongous()) {
_g1h->set_humongous_is_live(obj);
- } else if (state.is_optional()) {
+ } else if (region_attr.is_optional()) {
_par_scan_state->remember_reference_into_optional_region(p);
}
}
@@ -81,16 +81,16 @@
return;
}
oop obj = CompressedOops::decode_not_null(heap_oop);
- const InCSetState state = _g1h->in_cset_state(obj);
- if (state.is_in_cset()) {
+ const G1HeapRegionAttr region_attr = _g1h->region_attr(obj);
+ if (region_attr.is_in_cset()) {
prefetch_and_push(p, obj);
} else if (!HeapRegion::is_in_same_region(p, obj)) {
- handle_non_cset_obj_common(state, p, obj);
+ handle_non_cset_obj_common(region_attr, p, obj);
assert(_scanning_in_young != Uninitialized, "Scan location has not been initialized.");
if (_scanning_in_young == True) {
return;
}
- _par_scan_state->enqueue_card_if_tracked(p, obj);
+ _par_scan_state->enqueue_card_if_tracked(region_attr, p, obj);
}
}
@@ -160,7 +160,7 @@
}
template <class T>
-inline void G1ScanObjsDuringUpdateRSClosure::do_oop_work(T* p) {
+inline void G1ScanCardClosure::do_oop_work(T* p) {
T o = RawAccess<>::oop_load(p);
if (CompressedOops::is_null(o)) {
return;
@@ -169,31 +169,15 @@
check_obj_during_refinement(p, obj);
- assert(!_g1h->is_in_cset((HeapWord*)p), "Oop originates from " PTR_FORMAT " (region: %u) which is in the collection set.", p2i(p), _g1h->addr_to_region((HeapWord*)p));
- const InCSetState state = _g1h->in_cset_state(obj);
- if (state.is_in_cset()) {
- // Since the source is always from outside the collection set, here we implicitly know
- // that this is a cross-region reference too.
+ // We can not check for references from the collection set: the remembered sets
+ // may contain such entries and we do not filter them before.
+
+ const G1HeapRegionAttr region_attr = _g1h->region_attr(obj);
+ if (region_attr.is_in_cset()) {
prefetch_and_push(p, obj);
} else if (!HeapRegion::is_in_same_region(p, obj)) {
- handle_non_cset_obj_common(state, p, obj);
- _par_scan_state->enqueue_card_if_tracked(p, obj);
- }
-}
-
-template <class T>
-inline void G1ScanObjsDuringScanRSClosure::do_oop_work(T* p) {
- T heap_oop = RawAccess<>::oop_load(p);
- if (CompressedOops::is_null(heap_oop)) {
- return;
- }
- oop obj = CompressedOops::decode_not_null(heap_oop);
-
- const InCSetState state = _g1h->in_cset_state(obj);
- if (state.is_in_cset()) {
- prefetch_and_push(p, obj);
- } else if (!HeapRegion::is_in_same_region(p, obj)) {
- handle_non_cset_obj_common(state, p, obj);
+ handle_non_cset_obj_common(region_attr, p, obj);
+ _par_scan_state->enqueue_card_if_tracked(region_attr, p, obj);
}
}
@@ -233,7 +217,7 @@
assert(_worker_id == _par_scan_state->worker_id(), "sanity");
- const InCSetState state = _g1h->in_cset_state(obj);
+ const G1HeapRegionAttr state = _g1h->region_attr(obj);
if (state.is_in_cset()) {
oop forwardee;
markOop m = obj->mark_raw();
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp Wed May 15 13:54:43 2019 +0530
@@ -75,11 +75,11 @@
_plab_allocator = new G1PLABAllocator(_g1h->allocator());
- _dest[InCSetState::NotInCSet] = InCSetState::NotInCSet;
+ _dest[G1HeapRegionAttr::NotInCSet] = G1HeapRegionAttr::NotInCSet;
// The dest for Young is used when the objects are aged enough to
// need to be moved to the next space.
- _dest[InCSetState::Young] = InCSetState::Old;
- _dest[InCSetState::Old] = InCSetState::Old;
+ _dest[G1HeapRegionAttr::Young] = G1HeapRegionAttr::Old;
+ _dest[G1HeapRegionAttr::Old] = G1HeapRegionAttr::Old;
_closures = G1EvacuationRootClosures::create_root_closures(this, _g1h);
@@ -157,18 +157,18 @@
} while (!_refs->is_empty());
}
-HeapWord* G1ParScanThreadState::allocate_in_next_plab(InCSetState const state,
- InCSetState* dest,
+HeapWord* G1ParScanThreadState::allocate_in_next_plab(G1HeapRegionAttr const region_attr,
+ G1HeapRegionAttr* dest,
size_t word_sz,
bool previous_plab_refill_failed) {
- assert(state.is_in_cset_or_humongous(), "Unexpected state: " CSETSTATE_FORMAT, state.value());
- assert(dest->is_in_cset_or_humongous(), "Unexpected dest: " CSETSTATE_FORMAT, dest->value());
+ assert(region_attr.is_in_cset_or_humongous(), "Unexpected region attr type: %s", region_attr.get_type_str());
+ assert(dest->is_in_cset_or_humongous(), "Unexpected dest: %s region attr", dest->get_type_str());
// Right now we only have two types of regions (young / old) so
// let's keep the logic here simple. We can generalize it when necessary.
if (dest->is_young()) {
bool plab_refill_in_old_failed = false;
- HeapWord* const obj_ptr = _plab_allocator->allocate(InCSetState::Old,
+ HeapWord* const obj_ptr = _plab_allocator->allocate(G1HeapRegionAttr::Old,
word_sz,
&plab_refill_in_old_failed);
// Make sure that we won't attempt to copy any other objects out
@@ -190,38 +190,38 @@
return obj_ptr;
} else {
_old_gen_is_full = previous_plab_refill_failed;
- assert(dest->is_old(), "Unexpected dest: " CSETSTATE_FORMAT, dest->value());
+ assert(dest->is_old(), "Unexpected dest region attr: %s", dest->get_type_str());
// no other space to try.
return NULL;
}
}
-InCSetState G1ParScanThreadState::next_state(InCSetState const state, markOop const m, uint& age) {
- if (state.is_young()) {
+G1HeapRegionAttr G1ParScanThreadState::next_region_attr(G1HeapRegionAttr const region_attr, markOop const m, uint& age) {
+ if (region_attr.is_young()) {
age = !m->has_displaced_mark_helper() ? m->age()
: m->displaced_mark_helper()->age();
if (age < _tenuring_threshold) {
- return state;
+ return region_attr;
}
}
- return dest(state);
+ return dest(region_attr);
}
-void G1ParScanThreadState::report_promotion_event(InCSetState const dest_state,
+void G1ParScanThreadState::report_promotion_event(G1HeapRegionAttr const dest_attr,
oop const old, size_t word_sz, uint age,
HeapWord * const obj_ptr) const {
- PLAB* alloc_buf = _plab_allocator->alloc_buffer(dest_state);
+ PLAB* alloc_buf = _plab_allocator->alloc_buffer(dest_attr);
if (alloc_buf->contains(obj_ptr)) {
_g1h->_gc_tracer_stw->report_promotion_in_new_plab_event(old->klass(), word_sz * HeapWordSize, age,
- dest_state.value() == InCSetState::Old,
+ dest_attr.type() == G1HeapRegionAttr::Old,
alloc_buf->word_sz() * HeapWordSize);
} else {
_g1h->_gc_tracer_stw->report_promotion_outside_plab_event(old->klass(), word_sz * HeapWordSize, age,
- dest_state.value() == InCSetState::Old);
+ dest_attr.type() == G1HeapRegionAttr::Old);
}
}
-oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state,
+oop G1ParScanThreadState::copy_to_survivor_space(G1HeapRegionAttr const region_attr,
oop const old,
markOop const old_mark) {
const size_t word_sz = old->size();
@@ -232,21 +232,21 @@
(!from_region->is_young() && young_index == 0), "invariant" );
uint age = 0;
- InCSetState dest_state = next_state(state, old_mark, age);
+ G1HeapRegionAttr dest_attr = next_region_attr(region_attr, old_mark, age);
// The second clause is to prevent premature evacuation failure in case there
// is still space in survivor, but old gen is full.
- if (_old_gen_is_full && dest_state.is_old()) {
+ if (_old_gen_is_full && dest_attr.is_old()) {
return handle_evacuation_failure_par(old, old_mark);
}
- HeapWord* obj_ptr = _plab_allocator->plab_allocate(dest_state, word_sz);
+ HeapWord* obj_ptr = _plab_allocator->plab_allocate(dest_attr, word_sz);
// PLAB allocations should succeed most of the time, so we'll
// normally check against NULL once and that's it.
if (obj_ptr == NULL) {
bool plab_refill_failed = false;
- obj_ptr = _plab_allocator->allocate_direct_or_new_plab(dest_state, word_sz, &plab_refill_failed);
+ obj_ptr = _plab_allocator->allocate_direct_or_new_plab(dest_attr, word_sz, &plab_refill_failed);
if (obj_ptr == NULL) {
- obj_ptr = allocate_in_next_plab(state, &dest_state, word_sz, plab_refill_failed);
+ obj_ptr = allocate_in_next_plab(region_attr, &dest_attr, word_sz, plab_refill_failed);
if (obj_ptr == NULL) {
// This will either forward-to-self, or detect that someone else has
// installed a forwarding pointer.
@@ -255,7 +255,7 @@
}
if (_g1h->_gc_tracer_stw->should_report_promotion_events()) {
// The events are checked individually as part of the actual commit
- report_promotion_event(dest_state, old, word_sz, age, obj_ptr);
+ report_promotion_event(dest_attr, old, word_sz, age, obj_ptr);
}
}
@@ -267,7 +267,7 @@
if (_g1h->evacuation_should_fail()) {
// Doing this after all the allocation attempts also tests the
// undo_allocation() method too.
- _plab_allocator->undo_allocation(dest_state, obj_ptr, word_sz);
+ _plab_allocator->undo_allocation(dest_attr, obj_ptr, word_sz);
return handle_evacuation_failure_par(old, old_mark);
}
#endif // !PRODUCT
@@ -280,7 +280,7 @@
if (forward_ptr == NULL) {
Copy::aligned_disjoint_words((HeapWord*) old, obj_ptr, word_sz);
- if (dest_state.is_young()) {
+ if (dest_attr.is_young()) {
if (age < markOopDesc::max_age) {
age++;
}
@@ -300,8 +300,8 @@
}
if (G1StringDedup::is_enabled()) {
- const bool is_from_young = state.is_young();
- const bool is_to_young = dest_state.is_young();
+ const bool is_from_young = region_attr.is_young();
+ const bool is_to_young = dest_attr.is_young();
assert(is_from_young == _g1h->heap_region_containing(old)->is_young(),
"sanity");
assert(is_to_young == _g1h->heap_region_containing(obj)->is_young(),
@@ -322,12 +322,12 @@
oop* old_p = set_partial_array_mask(old);
do_oop_partial_array(old_p);
} else {
- G1ScanInYoungSetter x(&_scanner, dest_state.is_young());
+ G1ScanInYoungSetter x(&_scanner, dest_attr.is_young());
obj->oop_iterate_backwards(&_scanner);
}
return obj;
} else {
- _plab_allocator->undo_allocation(dest_state, obj_ptr, word_sz);
+ _plab_allocator->undo_allocation(dest_attr, obj_ptr, word_sz);
return forward_ptr;
}
}
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp Wed May 15 13:54:43 2019 +0530
@@ -45,17 +45,17 @@
class G1ParScanThreadState : public CHeapObj<mtGC> {
G1CollectedHeap* _g1h;
- RefToScanQueue* _refs;
+ RefToScanQueue* _refs;
G1DirtyCardQueue _dcq;
- G1CardTable* _ct;
+ G1CardTable* _ct;
G1EvacuationRootClosures* _closures;
- G1PLABAllocator* _plab_allocator;
+ G1PLABAllocator* _plab_allocator;
- AgeTable _age_table;
- InCSetState _dest[InCSetState::Num];
+ AgeTable _age_table;
+ G1HeapRegionAttr _dest[G1HeapRegionAttr::Num];
// Local tenuring threshold.
- uint _tenuring_threshold;
+ uint _tenuring_threshold;
G1ScanEvacuatedObjClosure _scanner;
uint _worker_id;
@@ -80,12 +80,12 @@
G1DirtyCardQueue& dirty_card_queue() { return _dcq; }
G1CardTable* ct() { return _ct; }
- InCSetState dest(InCSetState original) const {
+ G1HeapRegionAttr dest(G1HeapRegionAttr original) const {
assert(original.is_valid(),
- "Original state invalid: " CSETSTATE_FORMAT, original.value());
- assert(_dest[original.value()].is_valid_gen(),
- "Dest state is invalid: " CSETSTATE_FORMAT, _dest[original.value()].value());
- return _dest[original.value()];
+ "Original region attr invalid: %s", original.get_type_str());
+ assert(_dest[original.type()].is_valid_gen(),
+ "Dest region attr is invalid: %s", _dest[original.type()].get_type_str());
+ return _dest[original.type()];
}
size_t _num_optional_regions;
@@ -111,10 +111,19 @@
template <class T> void do_oop_ext(T* ref);
template <class T> void push_on_queue(T* ref);
- template <class T> void enqueue_card_if_tracked(T* p, oop o) {
+ template <class T> void enqueue_card_if_tracked(G1HeapRegionAttr region_attr, T* p, oop o) {
assert(!HeapRegion::is_in_same_region(p, o), "Should have filtered out cross-region references already.");
assert(!_g1h->heap_region_containing(p)->is_young(), "Should have filtered out from-young references already.");
- if (!_g1h->heap_region_containing((HeapWord*)o)->rem_set()->is_tracked()) {
+
+#ifdef ASSERT
+ HeapRegion* const hr_obj = _g1h->heap_region_containing((HeapWord*)o);
+ assert(region_attr.needs_remset_update() == hr_obj->rem_set()->is_tracked(),
+ "State flag indicating remset tracking disagrees (%s) with actual remembered set (%s) for region %u",
+ BOOL_TO_STR(region_attr.needs_remset_update()),
+ BOOL_TO_STR(hr_obj->rem_set()->is_tracked()),
+ hr_obj->hrm_index());
+#endif
+ if (!region_attr.needs_remset_update()) {
return;
}
size_t card_index = ct()->index_for(p);
@@ -184,14 +193,14 @@
// Returns a non-NULL pointer if successful, and updates dest if required.
// Also determines whether we should continue to try to allocate into the various
// generations or just end trying to allocate.
- HeapWord* allocate_in_next_plab(InCSetState const state,
- InCSetState* dest,
+ HeapWord* allocate_in_next_plab(G1HeapRegionAttr const region_attr,
+ G1HeapRegionAttr* dest,
size_t word_sz,
bool previous_plab_refill_failed);
- inline InCSetState next_state(InCSetState const state, markOop const m, uint& age);
+ inline G1HeapRegionAttr next_region_attr(G1HeapRegionAttr const region_attr, markOop const m, uint& age);
- void report_promotion_event(InCSetState const dest_state,
+ void report_promotion_event(G1HeapRegionAttr const dest_attr,
oop const old, size_t word_sz, uint age,
HeapWord * const obj_ptr) const;
@@ -200,7 +209,7 @@
inline void trim_queue_to_threshold(uint threshold);
public:
- oop copy_to_survivor_space(InCSetState const state, oop const obj, markOop const old_mark);
+ oop copy_to_survivor_space(G1HeapRegionAttr const region_attr, oop const obj, markOop const old_mark);
void trim_queue();
void trim_queue_partially();
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp Wed May 15 13:54:43 2019 +0530
@@ -41,14 +41,14 @@
// than one thread might claim the same card. So the same card may be
// processed multiple times, and so we might get references into old gen here.
// So we need to redo this check.
- const InCSetState in_cset_state = _g1h->in_cset_state(obj);
+ const G1HeapRegionAttr region_attr = _g1h->region_attr(obj);
// References pushed onto the work stack should never point to a humongous region
// as they are not added to the collection set due to above precondition.
- assert(!in_cset_state.is_humongous(),
+ assert(!region_attr.is_humongous(),
"Obj " PTR_FORMAT " should not refer to humongous region %u from " PTR_FORMAT,
p2i(obj), _g1h->addr_to_region((HeapWord*)obj), p2i(p));
- if (!in_cset_state.is_in_cset()) {
+ if (!region_attr.is_in_cset()) {
// In this case somebody else already did all the work.
return;
}
@@ -57,7 +57,7 @@
if (m->is_marked()) {
obj = (oop) m->decode_pointer();
} else {
- obj = copy_to_survivor_space(in_cset_state, obj, m);
+ obj = copy_to_survivor_space(region_attr, obj, m);
}
RawAccess<IS_NOT_NULL>::oop_store(p, obj);
@@ -67,7 +67,7 @@
}
HeapRegion* from = _g1h->heap_region_containing(p);
if (!from->is_young()) {
- enqueue_card_if_tracked(p, obj);
+ enqueue_card_if_tracked(_g1h->region_attr(obj), p, obj);
}
}
--- a/src/hotspot/share/gc/g1/g1Policy.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1Policy.hpp Wed May 15 13:54:43 2019 +0530
@@ -27,7 +27,7 @@
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1GCPhaseTimes.hpp"
-#include "gc/g1/g1InCSetState.hpp"
+#include "gc/g1/g1HeapRegionAttr.hpp"
#include "gc/g1/g1InitialMarkToMixedTimeTracker.hpp"
#include "gc/g1/g1MMUTracker.hpp"
#include "gc/g1/g1RemSetTrackingPolicy.hpp"
--- a/src/hotspot/share/gc/g1/g1RemSet.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1RemSet.cpp Wed May 15 13:54:43 2019 +0530
@@ -305,7 +305,7 @@
}
G1ScanRSForRegionClosure::G1ScanRSForRegionClosure(G1RemSetScanState* scan_state,
- G1ScanObjsDuringScanRSClosure* scan_obj_on_card,
+ G1ScanCardClosure* scan_obj_on_card,
G1ParScanThreadState* pss,
G1GCPhaseTimes::GCParPhases phase,
uint worker_i) :
@@ -345,7 +345,7 @@
G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r);
- G1ScanObjsDuringScanRSClosure scan_cl(_g1h, _pss);
+ G1ScanCardClosure scan_cl(_g1h, _pss);
G1ScanRSForOptionalClosure cl(&scan_cl);
_opt_refs_scanned += opt_rem_set_list->oops_do(&cl, _pss->closures()->raw_strong_oops());
_opt_refs_memory_used += opt_rem_set_list->used_memory();
@@ -464,7 +464,7 @@
G1GCPhaseTimes::GCParPhases coderoots_phase) {
assert(pss->trim_ticks().value() == 0, "Queues must have been trimmed before entering.");
- G1ScanObjsDuringScanRSClosure scan_cl(_g1h, pss);
+ G1ScanCardClosure scan_cl(_g1h, pss);
G1ScanRSForRegionClosure cl(_scan_state, &scan_cl, pss, scan_phase, worker_i);
_g1h->collection_set_iterate_increment_from(&cl, worker_i);
@@ -489,12 +489,12 @@
// Closure used for updating rem sets. Only called during an evacuation pause.
class G1RefineCardClosure: public G1CardTableEntryClosure {
G1RemSet* _g1rs;
- G1ScanObjsDuringUpdateRSClosure* _update_rs_cl;
+ G1ScanCardClosure* _update_rs_cl;
size_t _cards_scanned;
size_t _cards_skipped;
public:
- G1RefineCardClosure(G1CollectedHeap* g1h, G1ScanObjsDuringUpdateRSClosure* update_rs_cl) :
+ G1RefineCardClosure(G1CollectedHeap* g1h, G1ScanCardClosure* update_rs_cl) :
_g1rs(g1h->rem_set()), _update_rs_cl(update_rs_cl), _cards_scanned(0), _cards_skipped(0)
{}
@@ -527,7 +527,7 @@
if (G1HotCardCache::default_use_cache()) {
G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::ScanHCC, worker_i);
- G1ScanObjsDuringUpdateRSClosure scan_hcc_cl(_g1h, pss);
+ G1ScanCardClosure scan_hcc_cl(_g1h, pss);
G1RefineCardClosure refine_card_cl(_g1h, &scan_hcc_cl);
_g1h->iterate_hcc_closure(&refine_card_cl, worker_i);
}
@@ -536,7 +536,7 @@
{
G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::UpdateRS, worker_i);
- G1ScanObjsDuringUpdateRSClosure update_rs_cl(_g1h, pss);
+ G1ScanCardClosure update_rs_cl(_g1h, pss);
G1RefineCardClosure refine_card_cl(_g1h, &update_rs_cl);
_g1h->iterate_dirty_card_closure(&refine_card_cl, worker_i);
@@ -545,12 +545,12 @@
}
}
-void G1RemSet::prepare_for_oops_into_collection_set_do() {
+void G1RemSet::prepare_for_scan_rem_set() {
G1BarrierSet::dirty_card_queue_set().concatenate_logs();
_scan_state->reset();
}
-void G1RemSet::cleanup_after_oops_into_collection_set_do() {
+void G1RemSet::cleanup_after_scan_rem_set() {
G1GCPhaseTimes* phase_times = _g1h->phase_times();
// Set all cards back to clean.
@@ -712,7 +712,7 @@
}
bool G1RemSet::refine_card_during_gc(CardValue* card_ptr,
- G1ScanObjsDuringUpdateRSClosure* update_rs_cl) {
+ G1ScanCardClosure* update_rs_cl) {
assert(_g1h->is_gc_active(), "Only call during GC");
// Construct the region representing the card.
--- a/src/hotspot/share/gc/g1/g1RemSet.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1RemSet.hpp Wed May 15 13:54:43 2019 +0530
@@ -47,8 +47,7 @@
class G1RemSetScanState;
class G1ParScanThreadState;
class G1Policy;
-class G1ScanObjsDuringScanRSClosure;
-class G1ScanObjsDuringUpdateRSClosure;
+class G1ScanCardClosure;
class HeapRegionClaimer;
// A G1RemSet in which each heap region has a rem set that records the
@@ -99,11 +98,10 @@
// into the collection set or update the remembered set.
void update_rem_set(G1ParScanThreadState* pss, uint worker_i);
- // Prepare for and cleanup after an oops_into_collection_set_do
- // call. Must call each of these once before and after (in sequential
- // code) any thread calls oops_into_collection_set_do.
- void prepare_for_oops_into_collection_set_do();
- void cleanup_after_oops_into_collection_set_do();
+ // Prepare for and cleanup after scanning the remembered sets. Must be called
+ // once before and after in sequential code.
+ void prepare_for_scan_rem_set();
+ void cleanup_after_scan_rem_set();
G1RemSetScanState* scan_state() const { return _scan_state; }
@@ -115,7 +113,7 @@
// Refine the card corresponding to "card_ptr", applying the given closure to
// all references found. Must only be called during gc.
// Returns whether the card has been scanned.
- bool refine_card_during_gc(CardValue* card_ptr, G1ScanObjsDuringUpdateRSClosure* update_rs_cl);
+ bool refine_card_during_gc(CardValue* card_ptr, G1ScanCardClosure* update_rs_cl);
// Print accumulated summary info from the start of the VM.
void print_summary_info();
@@ -135,7 +133,7 @@
G1CardTable *_ct;
G1ParScanThreadState* _pss;
- G1ScanObjsDuringScanRSClosure* _scan_objs_on_card_cl;
+ G1ScanCardClosure* _scan_objs_on_card_cl;
G1RemSetScanState* _scan_state;
@@ -164,7 +162,7 @@
void scan_strong_code_roots(HeapRegion* r);
public:
G1ScanRSForRegionClosure(G1RemSetScanState* scan_state,
- G1ScanObjsDuringScanRSClosure* scan_obj_on_card,
+ G1ScanCardClosure* scan_obj_on_card,
G1ParScanThreadState* pss,
G1GCPhaseTimes::GCParPhases phase,
uint worker_i);
--- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp Wed May 15 13:54:43 2019 +0530
@@ -43,7 +43,7 @@
ShenandoahStore,
ShenandoahValue,
ShenandoahOopStore,
- ShenandoahNone,
+ ShenandoahNone
};
static bool verify_helper(Node* in, Node_Stack& phis, VectorSet& visited, verify_type t, bool trace, Unique_Node_List& barriers_used);
--- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp Wed May 15 13:54:43 2019 +0530
@@ -73,9 +73,9 @@
// ShenandoahGarbageThreshold is the soft threshold which would be ignored until min_garbage is hit.
size_t capacity = ShenandoahHeap::heap()->max_capacity();
- size_t free_target = ShenandoahMinFreeThreshold * capacity / 100;
+ size_t free_target = capacity / 100 * ShenandoahMinFreeThreshold;
size_t min_garbage = free_target > actual_free ? (free_target - actual_free) : 0;
- size_t max_cset = (size_t)(1.0 * ShenandoahEvacReserve * capacity / 100 / ShenandoahEvacWaste);
+ size_t max_cset = (size_t)((1.0 * capacity / 100 * ShenandoahEvacReserve) / ShenandoahEvacWaste);
log_info(gc, ergo)("Adaptive CSet Selection. Target Free: " SIZE_FORMAT "M, Actual Free: "
SIZE_FORMAT "M, Max CSet: " SIZE_FORMAT "M, Min Garbage: " SIZE_FORMAT "M",
@@ -128,7 +128,7 @@
// Check if we are falling below the worst limit, time to trigger the GC, regardless of
// anything else.
- size_t min_threshold = ShenandoahMinFreeThreshold * heap->max_capacity() / 100;
+ size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold;
if (available < min_threshold) {
log_info(gc)("Trigger: Free (" SIZE_FORMAT "M) is below minimum threshold (" SIZE_FORMAT "M)",
available / M, min_threshold / M);
@@ -138,7 +138,7 @@
// Check if are need to learn a bit about the application
const size_t max_learn = ShenandoahLearningSteps;
if (_gc_times_learned < max_learn) {
- size_t init_threshold = ShenandoahInitFreeThreshold * heap->max_capacity() / 100;
+ size_t init_threshold = capacity / 100 * ShenandoahInitFreeThreshold;
if (available < init_threshold) {
log_info(gc)("Trigger: Learning " SIZE_FORMAT " of " SIZE_FORMAT ". Free (" SIZE_FORMAT "M) is below initial threshold (" SIZE_FORMAT "M)",
_gc_times_learned + 1, max_learn, available / M, init_threshold / M);
@@ -152,8 +152,8 @@
size_t allocation_headroom = available;
- size_t spike_headroom = ShenandoahAllocSpikeFactor * capacity / 100;
- size_t penalties = _gc_time_penalties * capacity / 100;
+ size_t spike_headroom = capacity / 100 * ShenandoahAllocSpikeFactor;
+ size_t penalties = capacity / 100 * _gc_time_penalties;
allocation_headroom -= MIN2(allocation_headroom, spike_headroom);
allocation_headroom -= MIN2(allocation_headroom, penalties);
--- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp Wed May 15 13:54:43 2019 +0530
@@ -52,9 +52,11 @@
bool ShenandoahCompactHeuristics::should_start_normal_gc() const {
ShenandoahHeap* heap = ShenandoahHeap::heap();
+ size_t capacity = heap->max_capacity();
size_t available = heap->free_set()->available();
- size_t threshold_bytes_allocated = heap->max_capacity() * ShenandoahAllocationThreshold / 100;
- size_t min_threshold = ShenandoahMinFreeThreshold * heap->max_capacity() / 100;
+
+ size_t threshold_bytes_allocated = capacity / 100 * ShenandoahAllocationThreshold;
+ size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold;
if (available < min_threshold) {
log_info(gc)("Trigger: Free (" SIZE_FORMAT "M) is below minimum threshold (" SIZE_FORMAT "M)",
--- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp Wed May 15 13:54:43 2019 +0530
@@ -82,7 +82,7 @@
// Do not select too large CSet that would overflow the available free space.
// Take at least the entire evacuation reserve, and be free to overflow to free space.
size_t capacity = ShenandoahHeap::heap()->max_capacity();
- size_t available = MAX2(ShenandoahEvacReserve * capacity / 100, actual_free);
+ size_t available = MAX2(capacity / 100 * ShenandoahEvacReserve, actual_free);
size_t max_cset = (size_t)(available / ShenandoahEvacWaste);
log_info(gc, ergo)("CSet Selection. Actual Free: " SIZE_FORMAT "M, Max CSet: " SIZE_FORMAT "M",
--- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp Wed May 15 13:54:43 2019 +0530
@@ -54,7 +54,7 @@
size_t capacity = heap->max_capacity();
size_t available = heap->free_set()->available();
- size_t threshold_available = (capacity * ShenandoahFreeThreshold) / 100;
+ size_t threshold_available = capacity / 100 * ShenandoahFreeThreshold;
if (available < threshold_available) {
log_info(gc)("Trigger: Free (" SIZE_FORMAT "M) is below free threshold (" SIZE_FORMAT "M)",
--- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahTraversalHeuristics.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahTraversalHeuristics.cpp Wed May 15 13:54:43 2019 +0530
@@ -119,9 +119,9 @@
size_t capacity = heap->max_capacity();
size_t actual_free = heap->free_set()->available();
- size_t free_target = ShenandoahMinFreeThreshold * capacity / 100;
+ size_t free_target = capacity / 100 * ShenandoahMinFreeThreshold;
size_t min_garbage = free_target > actual_free ? (free_target - actual_free) : 0;
- size_t max_cset = (size_t)(1.0 * ShenandoahEvacReserve * capacity / 100 / ShenandoahEvacWaste);
+ size_t max_cset = (size_t)((1.0 * capacity / 100 * ShenandoahEvacReserve) / ShenandoahEvacWaste);
log_info(gc, ergo)("Adaptive CSet Selection. Target Free: " SIZE_FORMAT "M, Actual Free: "
SIZE_FORMAT "M, Max CSet: " SIZE_FORMAT "M, Min Garbage: " SIZE_FORMAT "M",
@@ -211,7 +211,7 @@
// Check if we are falling below the worst limit, time to trigger the GC, regardless of
// anything else.
- size_t min_threshold = ShenandoahMinFreeThreshold * heap->max_capacity() / 100;
+ size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold;
if (available < min_threshold) {
log_info(gc)("Trigger: Free (" SIZE_FORMAT "M) is below minimum threshold (" SIZE_FORMAT "M)",
available / M, min_threshold / M);
@@ -221,7 +221,7 @@
// Check if are need to learn a bit about the application
const size_t max_learn = ShenandoahLearningSteps;
if (_gc_times_learned < max_learn) {
- size_t init_threshold = ShenandoahInitFreeThreshold * heap->max_capacity() / 100;
+ size_t init_threshold = capacity / 100 * ShenandoahInitFreeThreshold;
if (available < init_threshold) {
log_info(gc)("Trigger: Learning " SIZE_FORMAT " of " SIZE_FORMAT ". Free (" SIZE_FORMAT "M) is below initial threshold (" SIZE_FORMAT "M)",
_gc_times_learned + 1, max_learn, available / M, init_threshold / M);
@@ -235,8 +235,8 @@
size_t allocation_headroom = available;
- size_t spike_headroom = ShenandoahAllocSpikeFactor * capacity / 100;
- size_t penalties = _gc_time_penalties * capacity / 100;
+ size_t spike_headroom = capacity / 100 * ShenandoahAllocSpikeFactor;
+ size_t penalties = capacity / 100 * _gc_time_penalties;
allocation_headroom -= MIN2(allocation_headroom, spike_headroom);
allocation_headroom -= MIN2(allocation_headroom, penalties);
--- a/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp Wed May 15 13:54:43 2019 +0530
@@ -33,7 +33,7 @@
_alloc_shared_gc, // Allocate common, outside of GCLAB
_alloc_tlab, // Allocate TLAB
_alloc_gclab, // Allocate GCLAB
- _ALLOC_LIMIT,
+ _ALLOC_LIMIT
};
static const char* alloc_type_to_string(Type type) {
--- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp Wed May 15 13:54:43 2019 +0530
@@ -204,7 +204,7 @@
void ShenandoahArguments::initialize_alignments() {
// Need to setup sizes early to get correct alignments.
- ShenandoahHeapRegion::setup_sizes(InitialHeapSize, MaxHeapSize);
+ ShenandoahHeapRegion::setup_sizes(MaxHeapSize);
// This is expected by our algorithm for ShenandoahHeap::heap_region_containing().
size_t align = ShenandoahHeapRegion::region_size_bytes();
--- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp Wed May 15 13:54:43 2019 +0530
@@ -35,7 +35,7 @@
_safe_unknown,
_safe_oop,
_safe_oop_fwd,
- _safe_all,
+ _safe_all
};
static void print_obj(ShenandoahMessageBuffer &msg, oop obj);
--- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp Wed May 15 13:54:43 2019 +0530
@@ -32,12 +32,13 @@
class ShenandoahBarrierSetAssembler;
class ShenandoahBarrierSet: public BarrierSet {
-private:
+public:
enum ArrayCopyStoreValMode {
NONE,
READ_BARRIER,
WRITE_BARRIER
};
+private:
ShenandoahHeap* _heap;
ShenandoahSATBMarkQueueSet _satb_mark_queue_set;
--- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp Wed May 15 13:54:43 2019 +0530
@@ -59,7 +59,7 @@
concurrent_traversal,
concurrent_normal,
stw_degenerated,
- stw_full,
+ stw_full
} GCMode;
// While we could have a single lock for these, it may risk unblocking
--- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp Wed May 15 13:54:43 2019 +0530
@@ -430,7 +430,7 @@
}
// Evac reserve: reserve trailing space for evacuations
- size_t to_reserve = ShenandoahEvacReserve * _heap->max_capacity() / 100;
+ size_t to_reserve = _heap->max_capacity() / 100 * ShenandoahEvacReserve;
size_t reserved = 0;
for (size_t idx = _heap->num_regions() - 1; idx > 0; idx--) {
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp Wed May 15 13:54:43 2019 +0530
@@ -244,7 +244,7 @@
UPDATEREFS_BITPOS = 3,
// Heap is under traversal collection
- TRAVERSAL_BITPOS = 4,
+ TRAVERSAL_BITPOS = 4
};
enum GCState {
@@ -253,7 +253,7 @@
MARKING = 1 << MARKING_BITPOS,
EVACUATION = 1 << EVACUATION_BITPOS,
UPDATEREFS = 1 << UPDATEREFS_BITPOS,
- TRAVERSAL = 1 << TRAVERSAL_BITPOS,
+ TRAVERSAL = 1 << TRAVERSAL_BITPOS
};
private:
@@ -303,7 +303,7 @@
_degenerated_mark,
_degenerated_evac,
_degenerated_updaterefs,
- _DEGENERATED_LIMIT,
+ _DEGENERATED_LIMIT
};
static const char* degen_point_to_string(ShenandoahDegenPoint point) {
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp Wed May 15 13:54:43 2019 +0530
@@ -516,7 +516,7 @@
}
}
-void ShenandoahHeapRegion::setup_sizes(size_t initial_heap_size, size_t max_heap_size) {
+void ShenandoahHeapRegion::setup_sizes(size_t max_heap_size) {
// Absolute minimums we should not ever break.
static const size_t MIN_REGION_SIZE = 256*K;
@@ -526,10 +526,10 @@
size_t region_size;
if (FLAG_IS_DEFAULT(ShenandoahHeapRegionSize)) {
- if (ShenandoahMinRegionSize > initial_heap_size / MIN_NUM_REGIONS) {
- err_msg message("Initial heap size (" SIZE_FORMAT "K) is too low to afford the minimum number "
+ if (ShenandoahMinRegionSize > max_heap_size / MIN_NUM_REGIONS) {
+ err_msg message("Max heap size (" SIZE_FORMAT "K) is too low to afford the minimum number "
"of regions (" SIZE_FORMAT ") of minimum region size (" SIZE_FORMAT "K).",
- initial_heap_size/K, MIN_NUM_REGIONS, ShenandoahMinRegionSize/K);
+ max_heap_size/K, MIN_NUM_REGIONS, ShenandoahMinRegionSize/K);
vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize option", message);
}
if (ShenandoahMinRegionSize < MIN_REGION_SIZE) {
@@ -562,10 +562,10 @@
region_size = MIN2(ShenandoahMaxRegionSize, region_size);
} else {
- if (ShenandoahHeapRegionSize > initial_heap_size / MIN_NUM_REGIONS) {
- err_msg message("Initial heap size (" SIZE_FORMAT "K) is too low to afford the minimum number "
+ if (ShenandoahHeapRegionSize > max_heap_size / MIN_NUM_REGIONS) {
+ err_msg message("Max heap size (" SIZE_FORMAT "K) is too low to afford the minimum number "
"of regions (" SIZE_FORMAT ") of requested size (" SIZE_FORMAT "K).",
- initial_heap_size/K, MIN_NUM_REGIONS, ShenandoahHeapRegionSize/K);
+ max_heap_size/K, MIN_NUM_REGIONS, ShenandoahHeapRegionSize/K);
vm_exit_during_initialization("Invalid -XX:ShenandoahHeapRegionSize option", message);
}
if (ShenandoahHeapRegionSize < ShenandoahMinRegionSize) {
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp Wed May 15 13:54:43 2019 +0530
@@ -114,7 +114,7 @@
_cset, // region is in collection set
_pinned, // region is pinned
_pinned_cset, // region is pinned and in cset (evac failure path)
- _trash, // region contains only trash
+ _trash // region contains only trash
};
const char* region_state_to_string(RegionState s) const {
@@ -257,7 +257,7 @@
static const size_t MIN_NUM_REGIONS = 10;
- static void setup_sizes(size_t initial_heap_size, size_t max_heap_size);
+ static void setup_sizes(size_t max_heap_size);
double empty_time() {
return _empty_time;
--- a/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.hpp Wed May 15 13:54:43 2019 +0530
@@ -39,7 +39,7 @@
enum PrivateConstants {
ValBuckets = 512,
MagBuckets = 24,
- MagMinimum = -12,
+ MagMinimum = -12
};
int** _hdr;
--- a/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahOopClosures.hpp Wed May 15 13:54:43 2019 +0530
@@ -41,7 +41,7 @@
enum StringDedupMode {
NO_DEDUP, // Do not do anything for String deduplication
- ENQUEUE_DEDUP, // Enqueue candidate Strings for deduplication
+ ENQUEUE_DEDUP // Enqueue candidate Strings for deduplication
};
class ShenandoahMarkRefsSuperClosure : public MetadataVisitingOopIterateClosure {
--- a/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp Wed May 15 13:54:43 2019 +0530
@@ -153,7 +153,7 @@
void ShenandoahPacer::setup_for_idle() {
assert(ShenandoahPacing, "Only be here when pacing is enabled");
- size_t initial = _heap->max_capacity() * ShenandoahPacingIdleSlack / 100;
+ size_t initial = _heap->max_capacity() / 100 * ShenandoahPacingIdleSlack;
double tax = 1;
restart_with(initial, tax);
--- a/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp Wed May 15 13:54:43 2019 +0530
@@ -35,7 +35,7 @@
typedef struct ShenandoahSharedFlag {
enum {
UNSET = 0,
- SET = 1,
+ SET = 1
};
DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile ShenandoahSharedValue));
@@ -62,8 +62,8 @@
return OrderAccess::load_acquire(&value) == UNSET;
}
- void set_cond(bool value) {
- if (value) {
+ void set_cond(bool val) {
+ if (val) {
set();
} else {
unset();
@@ -167,8 +167,8 @@
return (OrderAccess::load_acquire(&value)) == 0;
}
- void set_cond(uint mask, bool value) {
- if (value) {
+ void set_cond(uint mask, bool val) {
+ if (val) {
set(mask);
} else {
unset(mask);
--- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp Wed May 15 13:54:43 2019 +0530
@@ -125,12 +125,12 @@
enum {
chunk_bits = 10,
pow_bits = 5,
- oop_bits = sizeof(uintptr_t)*8 - chunk_bits - pow_bits,
+ oop_bits = sizeof(uintptr_t)*8 - chunk_bits - pow_bits
};
enum {
oop_shift = 0,
pow_shift = oop_shift + oop_bits,
- chunk_shift = pow_shift + pow_bits,
+ chunk_shift = pow_shift + pow_bits
};
public:
--- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp Wed May 15 13:54:43 2019 +0530
@@ -73,7 +73,7 @@
_verify_marked_incomplete,
// Objects should be marked in "complete" bitmap.
- _verify_marked_complete,
+ _verify_marked_complete
} VerifyMarked;
typedef enum {
@@ -84,7 +84,7 @@
_verify_forwarded_none,
// Objects may have forwardees.
- _verify_forwarded_allow,
+ _verify_forwarded_allow
} VerifyForwarded;
typedef enum {
@@ -97,7 +97,7 @@
// May have references to cset, all should be forwarded.
// Note: Allowing non-forwarded references to cset is equivalent
// to _verify_cset_disable.
- _verify_cset_forwarded,
+ _verify_cset_forwarded
} VerifyCollectionSet;
typedef enum {
@@ -109,7 +109,7 @@
// All objects should belong to live regions,
// and liveness data should be accurate
- _verify_liveness_complete,
+ _verify_liveness_complete
} VerifyLiveness;
typedef enum {
@@ -123,7 +123,7 @@
_verify_regions_nocset,
// No trash and no cset regions allowed
- _verify_regions_notrash_nocset,
+ _verify_regions_notrash_nocset
} VerifyRegions;
typedef enum {
@@ -137,7 +137,7 @@
_verify_gcstate_forwarded,
// Evacuation is in progress, some objects are forwarded
- _verify_gcstate_evacuation,
+ _verify_gcstate_evacuation
} VerifyGCState;
struct VerifyOptions {
--- a/src/hotspot/share/gc/z/vmStructs_z.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/vmStructs_z.hpp Wed May 15 13:54:43 2019 +0530
@@ -30,7 +30,6 @@
#include "gc/z/zGranuleMap.hpp"
#include "gc/z/zHeap.hpp"
#include "gc/z/zPageAllocator.hpp"
-#include "gc/z/zPhysicalMemory.hpp"
#include "utilities/macros.hpp"
// Expose some ZGC globals to the SA agent.
@@ -77,20 +76,18 @@
nonstatic_field(ZPage, _virtual, const ZVirtualMemory) \
volatile_nonstatic_field(ZPage, _top, uintptr_t) \
\
- nonstatic_field(ZPageAllocator, _physical, ZPhysicalMemoryManager) \
+ nonstatic_field(ZPageAllocator, _max_capacity, const size_t) \
+ nonstatic_field(ZPageAllocator, _capacity, size_t) \
nonstatic_field(ZPageAllocator, _used, size_t) \
\
nonstatic_field(ZPageTable, _map, ZGranuleMapForPageTable) \
\
nonstatic_field(ZGranuleMapForPageTable, _map, ZPage** const) \
\
- nonstatic_field(ZVirtualMemory, _start, uintptr_t) \
- nonstatic_field(ZVirtualMemory, _end, uintptr_t) \
+ nonstatic_field(ZVirtualMemory, _start, const uintptr_t) \
+ nonstatic_field(ZVirtualMemory, _end, const uintptr_t) \
\
- nonstatic_field(ZForwarding, _entries, const ZAttachedArrayForForwarding) \
- \
- nonstatic_field(ZPhysicalMemoryManager, _max_capacity, const size_t) \
- nonstatic_field(ZPhysicalMemoryManager, _capacity, size_t)
+ nonstatic_field(ZForwarding, _entries, const ZAttachedArrayForForwarding)
#define VM_INT_CONSTANTS_ZGC(declare_constant, declare_constant_with_value) \
declare_constant(ZPhaseRelocate) \
--- a/src/hotspot/share/gc/z/zCollectedHeap.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp Wed May 15 13:54:43 2019 +0530
@@ -48,6 +48,7 @@
_heap(),
_director(new ZDirector()),
_driver(new ZDriver()),
+ _uncommitter(new ZUncommitter()),
_stat(new ZStat()),
_runtime_workers() {}
@@ -77,6 +78,7 @@
void ZCollectedHeap::stop() {
_director->stop();
_driver->stop();
+ _uncommitter->stop();
_stat->stop();
}
@@ -272,6 +274,7 @@
void ZCollectedHeap::gc_threads_do(ThreadClosure* tc) const {
tc->do_thread(_director);
tc->do_thread(_driver);
+ tc->do_thread(_uncommitter);
tc->do_thread(_stat);
_heap.worker_threads_do(tc);
_runtime_workers.threads_do(tc);
@@ -331,6 +334,8 @@
st->cr();
_driver->print_on(st);
st->cr();
+ _uncommitter->print_on(st);
+ st->cr();
_stat->print_on(st);
st->cr();
_heap.print_worker_threads_on(st);
--- a/src/hotspot/share/gc/z/zCollectedHeap.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zCollectedHeap.hpp Wed May 15 13:54:43 2019 +0530
@@ -29,10 +29,11 @@
#include "gc/z/zBarrierSet.hpp"
#include "gc/z/zDirector.hpp"
#include "gc/z/zDriver.hpp"
+#include "gc/z/zHeap.hpp"
#include "gc/z/zInitialize.hpp"
-#include "gc/z/zHeap.hpp"
#include "gc/z/zRuntimeWorkers.hpp"
#include "gc/z/zStat.hpp"
+#include "gc/z/zUncommitter.hpp"
class ZCollectedHeap : public CollectedHeap {
friend class VMStructs;
@@ -44,6 +45,7 @@
ZHeap _heap;
ZDirector* _director;
ZDriver* _driver;
+ ZUncommitter* _uncommitter;
ZStat* _stat;
ZRuntimeWorkers _runtime_workers;
--- a/src/hotspot/share/gc/z/zHeap.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zHeap.cpp Wed May 15 13:54:43 2019 +0530
@@ -22,6 +22,7 @@
*/
#include "precompiled.hpp"
+#include "gc/shared/gcArguments.hpp"
#include "gc/shared/oopStorage.hpp"
#include "gc/z/zAddress.hpp"
#include "gc/z/zGlobals.hpp"
@@ -45,6 +46,7 @@
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
+#include "runtime/arguments.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/thread.hpp"
#include "utilities/align.hpp"
@@ -62,7 +64,7 @@
ZHeap::ZHeap() :
_workers(),
_object_allocator(_workers.nworkers()),
- _page_allocator(heap_min_size(), heap_max_size(), heap_max_reserve_size()),
+ _page_allocator(heap_min_size(), heap_initial_size(), heap_max_size(), heap_max_reserve_size()),
_page_table(),
_forwarding_table(),
_mark(&_workers, &_page_table),
@@ -81,13 +83,15 @@
}
size_t ZHeap::heap_min_size() const {
- const size_t aligned_min_size = align_up(InitialHeapSize, ZGranuleSize);
- return MIN2(aligned_min_size, heap_max_size());
+ return MinHeapSize;
+}
+
+size_t ZHeap::heap_initial_size() const {
+ return InitialHeapSize;
}
size_t ZHeap::heap_max_size() const {
- const size_t aligned_max_size = align_up(MaxHeapSize, ZGranuleSize);
- return MIN2(aligned_max_size, ZAddressOffsetMax);
+ return MaxHeapSize;
}
size_t ZHeap::heap_max_reserve_size() const {
@@ -102,7 +106,7 @@
}
size_t ZHeap::min_capacity() const {
- return heap_min_size();
+ return _page_allocator.min_capacity();
}
size_t ZHeap::max_capacity() const {
@@ -250,10 +254,14 @@
_page_allocator.free_page(page, reclaimed);
}
+uint64_t ZHeap::uncommit(uint64_t delay) {
+ return _page_allocator.uncommit(delay);
+}
+
void ZHeap::before_flip() {
if (ZVerifyViews) {
// Unmap all pages
- _page_allocator.unmap_all_pages();
+ _page_allocator.debug_unmap_all_pages();
}
}
@@ -262,8 +270,9 @@
// Map all pages
ZPageTableIterator iter(&_page_table);
for (ZPage* page; iter.next(&page);) {
- _page_allocator.map_page(page);
+ _page_allocator.debug_map_page(page);
}
+ _page_allocator.debug_map_cached_pages();
}
}
--- a/src/hotspot/share/gc/z/zHeap.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zHeap.hpp Wed May 15 13:54:43 2019 +0530
@@ -66,6 +66,7 @@
ZServiceability _serviceability;
size_t heap_min_size() const;
+ size_t heap_initial_size() const;
size_t heap_max_size() const;
size_t heap_max_reserve_size() const;
@@ -129,6 +130,9 @@
void undo_alloc_page(ZPage* page);
void free_page(ZPage* page, bool reclaimed);
+ // Uncommit memory
+ uint64_t uncommit(uint64_t delay);
+
// Object allocation
uintptr_t alloc_tlab(size_t size);
uintptr_t alloc_object(size_t size);
--- a/src/hotspot/share/gc/z/zList.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zList.hpp Wed May 15 13:54:43 2019 +0530
@@ -210,11 +210,11 @@
template <typename T, bool forward>
class ZListIteratorImpl : public StackObj {
private:
- ZList<T>* const _list;
- T* _next;
+ const ZList<T>* const _list;
+ T* _next;
public:
- ZListIteratorImpl(ZList<T>* list);
+ ZListIteratorImpl(const ZList<T>* list);
bool next(T** elem);
};
@@ -226,14 +226,14 @@
template <typename T>
class ZListIterator : public ZListIteratorImpl<T, ZLIST_FORWARD> {
public:
- ZListIterator(ZList<T>* list) :
+ ZListIterator(const ZList<T>* list) :
ZListIteratorImpl<T, ZLIST_FORWARD>(list) {}
};
template <typename T>
class ZListReverseIterator : public ZListIteratorImpl<T, ZLIST_REVERSE> {
public:
- ZListReverseIterator(ZList<T>* list) :
+ ZListReverseIterator(const ZList<T>* list) :
ZListIteratorImpl<T, ZLIST_REVERSE>(list) {}
};
--- a/src/hotspot/share/gc/z/zList.inline.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zList.inline.hpp Wed May 15 13:54:43 2019 +0530
@@ -27,7 +27,7 @@
#include "gc/z/zList.hpp"
template <typename T, bool forward>
-ZListIteratorImpl<T, forward>::ZListIteratorImpl(ZList<T>* list) :
+ZListIteratorImpl<T, forward>::ZListIteratorImpl(const ZList<T>* list) :
_list(list),
_next(forward ? list->first() : list->last()) {}
--- a/src/hotspot/share/gc/z/zLiveMap.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zLiveMap.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -34,15 +34,19 @@
static const ZStatCounter ZCounterMarkSeqNumResetContention("Contention", "Mark SeqNum Reset Contention", ZStatUnitOpsPerSecond);
static const ZStatCounter ZCounterMarkSegmentResetContention("Contention", "Mark Segment Reset Contention", ZStatUnitOpsPerSecond);
+static size_t bitmap_size(uint32_t size, size_t nsegments) {
+ // We need at least one bit per segment
+ return MAX2<size_t>(size, nsegments) * 2;
+}
+
ZLiveMap::ZLiveMap(uint32_t size) :
_seqnum(0),
_live_objects(0),
_live_bytes(0),
_segment_live_bits(0),
_segment_claim_bits(0),
- // We need at least one bit per segment.
- _bitmap(MAX2<size_t>(size, nsegments) * 2),
- _shift(exact_log2(segment_size())) {}
+ _bitmap(bitmap_size(size, nsegments)),
+ _segment_shift(exact_log2(segment_size())) {}
void ZLiveMap::reset(size_t index) {
const uint32_t seqnum_initializing = (uint32_t)-1;
@@ -121,3 +125,11 @@
const bool success = set_segment_live_atomic(segment);
assert(success, "Should never fail");
}
+
+void ZLiveMap::resize(uint32_t size) {
+ const size_t new_bitmap_size = bitmap_size(size, nsegments);
+ if (_bitmap.size() != new_bitmap_size) {
+ _bitmap.reinitialize(new_bitmap_size, false /* clear */);
+ _segment_shift = exact_log2(segment_size());
+ }
+}
--- a/src/hotspot/share/gc/z/zLiveMap.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zLiveMap.hpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -35,13 +35,13 @@
private:
static const size_t nsegments = 64;
- volatile uint32_t _seqnum; // Mark sequence number
- volatile uint32_t _live_objects; // Number of live objects
- volatile size_t _live_bytes; // Number of live bytes
- BitMap::bm_word_t _segment_live_bits; // Segment live bits
- BitMap::bm_word_t _segment_claim_bits; // Segment claim bits
- ZBitMap _bitmap; // Mark bitmap
- const size_t _shift; // Segment shift
+ volatile uint32_t _seqnum;
+ volatile uint32_t _live_objects;
+ volatile size_t _live_bytes;
+ BitMap::bm_word_t _segment_live_bits;
+ BitMap::bm_word_t _segment_claim_bits;
+ ZBitMap _bitmap;
+ size_t _segment_shift;
const BitMapView segment_live_bits() const;
const BitMapView segment_claim_bits() const;
@@ -72,6 +72,7 @@
ZLiveMap(uint32_t size);
void reset();
+ void resize(uint32_t size);
bool is_marked() const;
--- a/src/hotspot/share/gc/z/zLiveMap.inline.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zLiveMap.inline.hpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -92,7 +92,7 @@
}
inline BitMap::idx_t ZLiveMap::index_to_segment(BitMap::idx_t index) const {
- return index >> _shift;
+ return index >> _segment_shift;
}
inline bool ZLiveMap::get(size_t index) const {
--- a/src/hotspot/share/gc/z/zMemory.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zMemory.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -49,6 +49,30 @@
return UINTPTR_MAX;
}
+uintptr_t ZMemoryManager::alloc_from_front_at_most(size_t size, size_t* allocated) {
+ ZMemory* area = _freelist.first();
+ if (area != NULL) {
+ if (area->size() <= size) {
+ // Smaller than or equal to requested, remove area
+ const uintptr_t start = area->start();
+ *allocated = area->size();
+ _freelist.remove(area);
+ delete area;
+ return start;
+ } else {
+ // Larger than requested, shrink area
+ const uintptr_t start = area->start();
+ area->shrink_from_front(size);
+ *allocated = size;
+ return start;
+ }
+ }
+
+ // Out of memory
+ *allocated = 0;
+ return UINTPTR_MAX;
+}
+
uintptr_t ZMemoryManager::alloc_from_back(size_t size) {
ZListReverseIterator<ZMemory> iter(&_freelist);
for (ZMemory* area; iter.next(&area);) {
@@ -71,6 +95,29 @@
return UINTPTR_MAX;
}
+uintptr_t ZMemoryManager::alloc_from_back_at_most(size_t size, size_t* allocated) {
+ ZMemory* area = _freelist.last();
+ if (area != NULL) {
+ if (area->size() <= size) {
+ // Smaller than or equal to requested, remove area
+ const uintptr_t start = area->start();
+ *allocated = area->size();
+ _freelist.remove(area);
+ delete area;
+ return start;
+ } else {
+ // Larger than requested, shrink area
+ area->shrink_from_back(size);
+ *allocated = size;
+ return area->end();
+ }
+ }
+
+ // Out of memory
+ *allocated = 0;
+ return UINTPTR_MAX;
+}
+
void ZMemoryManager::free(uintptr_t start, size_t size) {
assert(start != UINTPTR_MAX, "Invalid address");
const uintptr_t end = start + size;
--- a/src/hotspot/share/gc/z/zMemory.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zMemory.hpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -54,7 +54,9 @@
public:
uintptr_t alloc_from_front(size_t size);
+ uintptr_t alloc_from_front_at_most(size_t size, size_t* allocated);
uintptr_t alloc_from_back(size_t size);
+ uintptr_t alloc_from_back_at_most(size_t size, size_t* allocated);
void free(uintptr_t start, size_t size);
};
--- a/src/hotspot/share/gc/z/zPage.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zPage.cpp Wed May 15 13:54:43 2019 +0530
@@ -28,30 +28,72 @@
#include "utilities/align.hpp"
#include "utilities/debug.hpp"
-ZPage::ZPage(uint8_t type, ZVirtualMemory vmem, ZPhysicalMemory pmem) :
+ZPage::ZPage(const ZVirtualMemory& vmem, const ZPhysicalMemory& pmem) :
+ _type(type_from_size(vmem.size())),
+ _numa_id((uint8_t)-1),
+ _seqnum(0),
+ _virtual(vmem),
+ _top(start()),
+ _livemap(object_max_count()),
+ _last_used(0),
+ _physical(pmem) {
+ assert_initialized();
+}
+
+ZPage::ZPage(uint8_t type, const ZVirtualMemory& vmem, const ZPhysicalMemory& pmem) :
_type(type),
_numa_id((uint8_t)-1),
_seqnum(0),
_virtual(vmem),
_top(start()),
_livemap(object_max_count()),
+ _last_used(0),
_physical(pmem) {
- assert(!_physical.is_null(), "Should not be null");
- assert(!_virtual.is_null(), "Should not be null");
- assert((type == ZPageTypeSmall && size() == ZPageSizeSmall) ||
- (type == ZPageTypeMedium && size() == ZPageSizeMedium) ||
- (type == ZPageTypeLarge && is_aligned(size(), ZGranuleSize)),
- "Page type/size mismatch");
+ assert_initialized();
}
-ZPage::~ZPage() {
- assert(_physical.is_null(), "Should be null");
+void ZPage::assert_initialized() const {
+ assert(!_virtual.is_null(), "Should not be null");
+ assert(!_physical.is_null(), "Should not be null");
+ assert((_type == ZPageTypeSmall && size() == ZPageSizeSmall) ||
+ (_type == ZPageTypeMedium && size() == ZPageSizeMedium) ||
+ (_type == ZPageTypeLarge && is_aligned(size(), ZGranuleSize)),
+ "Page type/size mismatch");
}
void ZPage::reset() {
_seqnum = ZGlobalSeqNum;
_top = start();
_livemap.reset();
+ _last_used = 0;
+}
+
+ZPage* ZPage::retype(uint8_t type) {
+ assert(_type != type, "Invalid retype");
+ _type = type;
+ _livemap.resize(object_max_count());
+ return this;
+}
+
+ZPage* ZPage::split(size_t size) {
+ return split(type_from_size(size), size);
+}
+
+ZPage* ZPage::split(uint8_t type, size_t size) {
+ assert(_virtual.size() > size, "Invalid split");
+
+ // Resize this page, keep _numa_id, _seqnum, and _last_used
+ const ZVirtualMemory vmem = _virtual.split(size);
+ const ZPhysicalMemory pmem = _physical.split(size);
+ _type = type_from_size(_virtual.size());
+ _top = start();
+ _livemap.resize(object_max_count());
+
+ // Create new page, inherit _seqnum and _last_used
+ ZPage* const page = new ZPage(type, vmem, pmem);
+ page->_seqnum = _seqnum;
+ page->_last_used = _last_used;
+ return page;
}
void ZPage::print_on(outputStream* out) const {
--- a/src/hotspot/share/gc/z/zPage.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zPage.hpp Wed May 15 13:54:43 2019 +0530
@@ -35,26 +35,27 @@
friend class ZList<ZPage>;
private:
- // Always hot
- const uint8_t _type; // Page type
- uint8_t _numa_id; // NUMA node affinity
- uint32_t _seqnum; // Allocation sequence number
- const ZVirtualMemory _virtual; // Virtual start/end address
- volatile uintptr_t _top; // Virtual top address
- ZLiveMap _livemap; // Live map
+ uint8_t _type;
+ uint8_t _numa_id;
+ uint32_t _seqnum;
+ ZVirtualMemory _virtual;
+ volatile uintptr_t _top;
+ ZLiveMap _livemap;
+ uint64_t _last_used;
+ ZPhysicalMemory _physical;
+ ZListNode<ZPage> _node;
- // Hot when relocated and cached
- ZPhysicalMemory _physical; // Physical memory for page
- ZListNode<ZPage> _node; // Page list node
+ void assert_initialized() const;
+ uint8_t type_from_size(size_t size) const;
const char* type_to_string() const;
bool is_object_marked(uintptr_t addr) const;
bool is_object_strongly_marked(uintptr_t addr) const;
public:
- ZPage(uint8_t type, ZVirtualMemory vmem, ZPhysicalMemory pmem);
- ~ZPage();
+ ZPage(const ZVirtualMemory& vmem, const ZPhysicalMemory& pmem);
+ ZPage(uint8_t type, const ZVirtualMemory& vmem, const ZPhysicalMemory& pmem);
uint32_t object_max_count() const;
size_t object_alignment_shift() const;
@@ -67,17 +68,10 @@
uintptr_t top() const;
size_t remaining() const;
- uint8_t numa_id();
-
- ZPhysicalMemory& physical_memory();
+ const ZPhysicalMemory& physical_memory() const;
const ZVirtualMemory& virtual_memory() const;
- void reset();
-
- bool is_in(uintptr_t addr) const;
-
- uintptr_t block_start(uintptr_t addr) const;
- bool block_is_obj(uintptr_t addr) const;
+ uint8_t numa_id();
bool is_allocating() const;
bool is_relocatable() const;
@@ -85,6 +79,20 @@
bool is_mapped() const;
void set_pre_mapped();
+ uint64_t last_used() const;
+ void set_last_used();
+
+ void reset();
+
+ ZPage* retype(uint8_t type);
+ ZPage* split(size_t size);
+ ZPage* split(uint8_t type, size_t size);
+
+ bool is_in(uintptr_t addr) const;
+
+ uintptr_t block_start(uintptr_t addr) const;
+ bool block_is_obj(uintptr_t addr) const;
+
bool is_marked() const;
bool is_object_live(uintptr_t addr) const;
bool is_object_strongly_live(uintptr_t addr) const;
--- a/src/hotspot/share/gc/z/zPage.inline.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zPage.inline.hpp Wed May 15 13:54:43 2019 +0530
@@ -34,10 +34,23 @@
#include "gc/z/zVirtualMemory.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/atomic.hpp"
-#include "runtime/orderAccess.hpp"
+#include "runtime/os.hpp"
#include "utilities/align.hpp"
#include "utilities/debug.hpp"
+inline uint8_t ZPage::type_from_size(size_t size) const {
+ switch (size) {
+ case ZPageSizeSmall:
+ return ZPageTypeSmall;
+
+ case ZPageSizeMedium:
+ return ZPageTypeMedium;
+
+ default:
+ return ZPageTypeLarge;
+ }
+}
+
inline const char* ZPage::type_to_string() const {
switch (type()) {
case ZPageTypeSmall:
@@ -116,7 +129,7 @@
return end() - top();
}
-inline ZPhysicalMemory& ZPage::physical_memory() {
+inline const ZPhysicalMemory& ZPage::physical_memory() const {
return _physical;
}
@@ -132,23 +145,6 @@
return _numa_id;
}
-inline bool ZPage::is_in(uintptr_t addr) const {
- const uintptr_t offset = ZAddress::offset(addr);
- return offset >= start() && offset < top();
-}
-
-inline uintptr_t ZPage::block_start(uintptr_t addr) const {
- if (block_is_obj(addr)) {
- return addr;
- } else {
- return ZAddress::good(top());
- }
-}
-
-inline bool ZPage::block_is_obj(uintptr_t addr) const {
- return ZAddress::offset(addr) < top();
-}
-
inline bool ZPage::is_allocating() const {
return _seqnum == ZGlobalSeqNum;
}
@@ -168,6 +164,31 @@
_seqnum = 1;
}
+inline uint64_t ZPage::last_used() const {
+ return _last_used;
+}
+
+inline void ZPage::set_last_used() {
+ _last_used = os::elapsedTime();
+}
+
+inline bool ZPage::is_in(uintptr_t addr) const {
+ const uintptr_t offset = ZAddress::offset(addr);
+ return offset >= start() && offset < top();
+}
+
+inline uintptr_t ZPage::block_start(uintptr_t addr) const {
+ if (block_is_obj(addr)) {
+ return addr;
+ } else {
+ return ZAddress::good(top());
+ }
+}
+
+inline bool ZPage::block_is_obj(uintptr_t addr) const {
+ return ZAddress::offset(addr) < top();
+}
+
inline bool ZPage::is_marked() const {
assert(is_relocatable(), "Invalid page state");
return _livemap.is_marked();
--- a/src/hotspot/share/gc/z/zPageAllocator.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zPageAllocator.cpp Wed May 15 13:54:43 2019 +0530
@@ -22,6 +22,7 @@
*/
#include "precompiled.hpp"
+#include "gc/shared/suspendibleThreadSet.hpp"
#include "gc/z/zAddress.inline.hpp"
#include "gc/z/zCollectedHeap.hpp"
#include "gc/z/zFuture.inline.hpp"
@@ -30,14 +31,16 @@
#include "gc/z/zPage.inline.hpp"
#include "gc/z/zPageAllocator.hpp"
#include "gc/z/zPageCache.inline.hpp"
-#include "gc/z/zPreMappedMemory.inline.hpp"
#include "gc/z/zSafeDelete.inline.hpp"
#include "gc/z/zStat.hpp"
#include "gc/z/zTracer.inline.hpp"
#include "runtime/init.hpp"
+#include "runtime/java.hpp"
+#include "utilities/debug.hpp"
static const ZStatCounter ZCounterAllocationRate("Memory", "Allocation Rate", ZStatUnitBytesPerSecond);
-static const ZStatCounter ZCounterPageCacheEvict("Memory", "Page Cache Evict", ZStatUnitBytesPerSecond);
+static const ZStatCounter ZCounterPageCacheFlush("Memory", "Page Cache Flush", ZStatUnitBytesPerSecond);
+static const ZStatCounter ZCounterUncommit("Memory", "Uncommit", ZStatUnitBytesPerSecond);
static const ZStatCriticalPhase ZCriticalPhaseAllocationStall("Allocation Stall");
class ZPageAllocRequest : public StackObj {
@@ -85,37 +88,105 @@
ZPage* const ZPageAllocator::gc_marker = (ZPage*)-1;
-ZPageAllocator::ZPageAllocator(size_t min_capacity, size_t max_capacity, size_t max_reserve) :
+ZPageAllocator::ZPageAllocator(size_t min_capacity,
+ size_t initial_capacity,
+ size_t max_capacity,
+ size_t max_reserve) :
_lock(),
_virtual(),
- _physical(max_capacity),
+ _physical(),
_cache(),
+ _min_capacity(min_capacity),
+ _max_capacity(max_capacity),
_max_reserve(max_reserve),
- _pre_mapped(_virtual, _physical, try_ensure_unused_for_pre_mapped(min_capacity)),
+ _current_max_capacity(max_capacity),
+ _capacity(0),
_used_high(0),
_used_low(0),
_used(0),
_allocated(0),
_reclaimed(0),
_queue(),
- _safe_delete() {}
+ _safe_delete(),
+ _uncommit(false),
+ _initialized(false) {
+
+ if (!_virtual.is_initialized() || !_physical.is_initialized()) {
+ return;
+ }
+
+ log_info(gc, init)("Min Capacity: " SIZE_FORMAT "M", min_capacity / M);
+ log_info(gc, init)("Initial Capacity: " SIZE_FORMAT "M", initial_capacity / M);
+ log_info(gc, init)("Max Capacity: " SIZE_FORMAT "M", max_capacity / M);
+ log_info(gc, init)("Max Reserve: " SIZE_FORMAT "M", max_reserve / M);
+ log_info(gc, init)("Pre-touch: %s", AlwaysPreTouch ? "Enabled" : "Disabled");
+
+ // Warn if system limits could stop us from reaching max capacity
+ _physical.warn_commit_limits(max_capacity);
+
+ // Commit initial capacity
+ _capacity = _physical.commit(initial_capacity);
+ if (_capacity != initial_capacity) {
+ log_error(gc)("Failed to allocate initial Java heap (" SIZE_FORMAT "M)", initial_capacity / M);
+ return;
+ }
+
+ // If uncommit is not explicitly disabled, max capacity is greater than
+ // min capacity, and uncommit is supported by the platform, then we will
+ // try to uncommit unused memory.
+ _uncommit = ZUncommit && (max_capacity > min_capacity) && _physical.supports_uncommit();
+ if (_uncommit) {
+ log_info(gc, init)("Uncommit: Enabled, Delay: " UINTX_FORMAT "s", ZUncommitDelay);
+ } else {
+ log_info(gc, init)("Uncommit: Disabled");
+ }
+
+ // Pre-map initial capacity
+ prime_cache(initial_capacity);
+
+ // Successfully initialized
+ _initialized = true;
+}
+
+void ZPageAllocator::prime_cache(size_t size) {
+ // Allocate physical memory
+ const ZPhysicalMemory pmem = _physical.alloc(size);
+ guarantee(!pmem.is_null(), "Invalid size");
+
+ // Allocate virtual memory
+ const ZVirtualMemory vmem = _virtual.alloc(size, true /* alloc_from_front */);
+ guarantee(!vmem.is_null(), "Invalid size");
+
+ // Allocate page
+ ZPage* const page = new ZPage(vmem, pmem);
+
+ // Map page
+ map_page(page);
+ page->set_pre_mapped();
+
+ // Add page to cache
+ page->set_last_used();
+ _cache.free_page(page);
+}
bool ZPageAllocator::is_initialized() const {
- return _physical.is_initialized() &&
- _virtual.is_initialized() &&
- _pre_mapped.is_initialized();
+ return _initialized;
+}
+
+size_t ZPageAllocator::min_capacity() const {
+ return _min_capacity;
}
size_t ZPageAllocator::max_capacity() const {
- return _physical.max_capacity();
+ return _max_capacity;
}
size_t ZPageAllocator::current_max_capacity() const {
- return _physical.current_max_capacity();
+ return _current_max_capacity;
}
size_t ZPageAllocator::capacity() const {
- return _physical.capacity();
+ return _capacity;
}
size_t ZPageAllocator::max_reserve() const {
@@ -135,7 +206,7 @@
}
size_t ZPageAllocator::unused() const {
- const ssize_t unused = (ssize_t)_physical.capacity() - (ssize_t)_used - (ssize_t)_max_reserve;
+ const ssize_t unused = (ssize_t)_capacity - (ssize_t)_used - (ssize_t)_max_reserve;
return unused > 0 ? (size_t)unused : 0;
}
@@ -181,83 +252,40 @@
}
}
-size_t ZPageAllocator::max_available(bool no_reserve) const {
- size_t available = current_max_capacity() - used();
-
- if (no_reserve) {
- // The reserve should not be considered available
- available -= MIN2(available, max_reserve());
- }
-
- return available;
-}
-
-size_t ZPageAllocator::try_ensure_unused(size_t size, bool no_reserve) {
- // Ensure that we always have space available for the reserve. This
- // is needed to avoid losing the reserve because of failure to map
- // more memory before reaching max capacity.
- _physical.try_ensure_unused_capacity(size + max_reserve());
-
- size_t unused = _physical.unused_capacity();
-
- if (no_reserve) {
- // The reserve should not be considered unused
- unused -= MIN2(unused, max_reserve());
- }
-
- return MIN2(size, unused);
-}
-
-size_t ZPageAllocator::try_ensure_unused_for_pre_mapped(size_t size) {
- // This function is called during construction, where the
- // physical memory manager might have failed to initialied.
- if (!_physical.is_initialized()) {
- return 0;
- }
-
- return try_ensure_unused(size, true /* no_reserve */);
-}
-
ZPage* ZPageAllocator::create_page(uint8_t type, size_t size) {
- // Allocate physical memory
- const ZPhysicalMemory pmem = _physical.alloc(size);
- if (pmem.is_null()) {
- // Out of memory
- return NULL;
- }
-
// Allocate virtual memory
const ZVirtualMemory vmem = _virtual.alloc(size);
if (vmem.is_null()) {
// Out of address space
- _physical.free(pmem);
return NULL;
}
+ // Allocate physical memory
+ const ZPhysicalMemory pmem = _physical.alloc(size);
+ assert(!pmem.is_null(), "Invalid size");
+
// Allocate page
return new ZPage(type, vmem, pmem);
}
-void ZPageAllocator::flush_pre_mapped() {
- if (_pre_mapped.available() == 0) {
- return;
- }
+void ZPageAllocator::destroy_page(ZPage* page) {
+ const ZVirtualMemory& vmem = page->virtual_memory();
+ const ZPhysicalMemory& pmem = page->physical_memory();
- // Detach the memory mapping.
- detach_memory(_pre_mapped.virtual_memory(), _pre_mapped.physical_memory());
+ // Unmap memory
+ _physical.unmap(pmem, vmem.start());
- _pre_mapped.clear();
-}
+ // Free physical memory
+ _physical.free(pmem);
-void ZPageAllocator::destroy_page(ZPage* page) {
- // Detach virtual and physical memory
- detach_memory(page->virtual_memory(), page->physical_memory());
+ // Free virtual memory
+ _virtual.free(vmem);
// Delete page safely
_safe_delete(page);
}
-void ZPageAllocator::map_page(ZPage* page) {
+void ZPageAllocator::map_page(const ZPage* page) const {
// Map physical memory
if (!page->is_mapped()) {
_physical.map(page->physical_memory(), page->start());
@@ -266,57 +294,92 @@
}
}
-void ZPageAllocator::unmap_all_pages() {
- ZPhysicalMemory pmem(ZPhysicalMemorySegment(0 /* start */, ZAddressOffsetMax));
- _physical.debug_unmap(pmem, 0 /* offset */);
- pmem.clear();
+size_t ZPageAllocator::max_available(bool no_reserve) const {
+ size_t available = _current_max_capacity - _used;
+
+ if (no_reserve) {
+ // The reserve should not be considered available
+ available -= MIN2(available, _max_reserve);
+ }
+
+ return available;
}
-void ZPageAllocator::check_out_of_memory_during_initialization() {
- if (!is_init_completed()) {
- vm_exit_during_initialization("java.lang.OutOfMemoryError", "Java heap too small");
+bool ZPageAllocator::ensure_available(size_t size, bool no_reserve) {
+ if (max_available(no_reserve) < size) {
+ // Not enough free memory
+ return false;
+ }
+
+ // We add the max_reserve to the requested size to avoid losing
+ // the reserve because of failure to increase capacity before
+ // reaching max capacity.
+ size += _max_reserve;
+
+ // Don't try to increase capacity if enough unused capacity
+ // is available or if current max capacity has been reached.
+ const size_t available = _capacity - _used;
+ if (available < size && _capacity < _current_max_capacity) {
+ // Try to increase capacity
+ const size_t commit = MIN2(size - available, _current_max_capacity - _capacity);
+ const size_t committed = _physical.commit(commit);
+ _capacity += committed;
+
+ log_trace(gc, heap)("Make Available: Size: " SIZE_FORMAT "M, NoReserve: %s, "
+ "Available: " SIZE_FORMAT "M, Commit: " SIZE_FORMAT "M, "
+ "Committed: " SIZE_FORMAT "M, Capacity: " SIZE_FORMAT "M",
+ size / M, no_reserve ? "True" : "False", available / M,
+ commit / M, committed / M, _capacity / M);
+
+ if (committed != commit) {
+ // Failed, or partly failed, to increase capacity. Adjust current
+ // max capacity to avoid further attempts to increase capacity.
+ log_error(gc)("Forced to lower max Java heap size from "
+ SIZE_FORMAT "M(%.0lf%%) to " SIZE_FORMAT "M(%.0lf%%)",
+ _current_max_capacity / M, percent_of(_current_max_capacity, _max_capacity),
+ _capacity / M, percent_of(_capacity, _max_capacity));
+
+ _current_max_capacity = _capacity;
+ }
+ }
+
+ if (!no_reserve) {
+ size -= _max_reserve;
+ }
+
+ const size_t new_available = _capacity - _used;
+ return new_available >= size;
+}
+
+void ZPageAllocator::ensure_uncached_available(size_t size) {
+ assert(_capacity - _used >= size, "Invalid size");
+ const size_t uncached_available = _capacity - _used - _cache.available();
+ if (size > uncached_available) {
+ flush_cache_for_allocation(size - uncached_available);
}
}
-ZPage* ZPageAllocator::alloc_page_common_inner(uint8_t type, size_t size, ZAllocationFlags flags) {
- const size_t max = max_available(flags.no_reserve());
- if (max < size) {
+ZPage* ZPageAllocator::alloc_page_common_inner(uint8_t type, size_t size, bool no_reserve) {
+ if (!ensure_available(size, no_reserve)) {
// Not enough free memory
return NULL;
}
- // Try allocating from the page cache
- ZPage* const cached_page = _cache.alloc_page(type, size);
- if (cached_page != NULL) {
- return cached_page;
- }
-
- // Try allocate from the pre-mapped memory
- ZPage* const pre_mapped_page = _pre_mapped.alloc_page(type, size);
- if (pre_mapped_page != NULL) {
- return pre_mapped_page;
+ // Try allocate page from the cache
+ ZPage* const page = _cache.alloc_page(type, size);
+ if (page != NULL) {
+ return page;
}
- // Flush any remaining pre-mapped memory so that
- // subsequent allocations can use the physical memory.
- flush_pre_mapped();
+ // Try flush pages from the cache
+ ensure_uncached_available(size);
- // Try ensure that physical memory is available
- const size_t unused = try_ensure_unused(size, flags.no_reserve());
- if (unused < size) {
- // Try evict pages from the cache
- const size_t needed = size - unused;
- if (_cache.available() >= needed) {
- evict_cache(needed);
- }
- }
-
- // Create new page and allocate physical memory
+ // Create new page
return create_page(type, size);
}
ZPage* ZPageAllocator::alloc_page_common(uint8_t type, size_t size, ZAllocationFlags flags) {
- ZPage* const page = alloc_page_common_inner(type, size, flags);
+ ZPage* const page = alloc_page_common_inner(type, size, flags.no_reserve());
if (page == NULL) {
// Out of memory
return NULL;
@@ -326,11 +389,17 @@
increase_used(size, flags.relocation());
// Send trace event
- ZTracer::tracer()->report_page_alloc(size, used(), max_available(flags.no_reserve()), _cache.available(), flags);
+ ZTracer::tracer()->report_page_alloc(size, _used, max_available(flags.no_reserve()), _cache.available(), flags);
return page;
}
+void ZPageAllocator::check_out_of_memory_during_initialization() {
+ if (!is_init_completed()) {
+ vm_exit_during_initialization("java.lang.OutOfMemoryError", "Java heap too small");
+ }
+}
+
ZPage* ZPageAllocator::alloc_page_blocking(uint8_t type, size_t size, ZAllocationFlags flags) {
// Prepare to block
ZPageAllocRequest request(type, size, flags, ZCollectedHeap::heap()->total_collections());
@@ -433,28 +502,15 @@
}
}
-void ZPageAllocator::detach_memory(const ZVirtualMemory& vmem, ZPhysicalMemory& pmem) {
- const uintptr_t addr = vmem.start();
-
- // Free virtual memory
- _virtual.free(vmem);
-
- // Unmap physical memory
- _physical.unmap(pmem, addr);
-
- // Free physical memory
- _physical.free(pmem);
-
- // Clear physical mapping
- pmem.clear();
-}
-
void ZPageAllocator::free_page(ZPage* page, bool reclaimed) {
ZLocker<ZLock> locker(&_lock);
// Update used statistics
decrease_used(page->size(), reclaimed);
+ // Set time when last used
+ page->set_last_used();
+
// Cache page
_cache.free_page(page);
@@ -462,59 +518,157 @@
satisfy_alloc_queue();
}
-void ZPageAllocator::flush_cache(ZPageCacheFlushClosure* cl) {
+size_t ZPageAllocator::flush_cache(ZPageCacheFlushClosure* cl) {
ZList<ZPage> list;
+ // Flush pages
_cache.flush(cl, &list);
+ const size_t overflushed = cl->overflushed();
+ if (overflushed > 0) {
+ // Overflushed, keep part of last page
+ ZPage* const page = list.last()->split(overflushed);
+ _cache.free_page(page);
+ }
+
+ // Destroy pages
+ size_t flushed = 0;
for (ZPage* page = list.remove_first(); page != NULL; page = list.remove_first()) {
+ flushed += page->size();
destroy_page(page);
}
+
+ return flushed;
}
-class ZPageCacheEvictClosure : public ZPageCacheFlushClosure {
-private:
- const size_t _requested;
- size_t _evicted;
-
+class ZPageCacheFlushForAllocationClosure : public ZPageCacheFlushClosure {
public:
- ZPageCacheEvictClosure(size_t requested) :
- _requested(requested),
- _evicted(0) {}
+ ZPageCacheFlushForAllocationClosure(size_t requested) :
+ ZPageCacheFlushClosure(requested) {}
virtual bool do_page(const ZPage* page) {
- if (_evicted < _requested) {
- // Evict page
- _evicted += page->size();
+ if (_flushed < _requested) {
+ // Flush page
+ _flushed += page->size();
return true;
}
- // Don't evict page
+ // Don't flush page
return false;
}
-
- size_t evicted() const {
- return _evicted;
- }
};
-void ZPageAllocator::evict_cache(size_t requested) {
- // Evict pages
- ZPageCacheEvictClosure cl(requested);
- flush_cache(&cl);
+void ZPageAllocator::flush_cache_for_allocation(size_t requested) {
+ assert(requested <= _cache.available(), "Invalid request");
- const size_t evicted = cl.evicted();
+ // Flush pages
+ ZPageCacheFlushForAllocationClosure cl(requested);
+ const size_t flushed = flush_cache(&cl);
+
+ assert(requested == flushed, "Failed to flush");
+
const size_t cached_after = _cache.available();
- const size_t cached_before = cached_after + evicted;
+ const size_t cached_before = cached_after + flushed;
log_info(gc, heap)("Page Cache: " SIZE_FORMAT "M(%.0lf%%)->" SIZE_FORMAT "M(%.0lf%%), "
- "Evicted: " SIZE_FORMAT "M, Requested: " SIZE_FORMAT "M",
+ "Flushed: " SIZE_FORMAT "M",
cached_before / M, percent_of(cached_before, max_capacity()),
cached_after / M, percent_of(cached_after, max_capacity()),
- evicted / M, requested / M);
+ flushed / M);
// Update statistics
- ZStatInc(ZCounterPageCacheEvict, evicted);
+ ZStatInc(ZCounterPageCacheFlush, flushed);
+}
+
+class ZPageCacheFlushForUncommitClosure : public ZPageCacheFlushClosure {
+private:
+ const uint64_t _now;
+ const uint64_t _delay;
+ uint64_t _timeout;
+
+public:
+ ZPageCacheFlushForUncommitClosure(size_t requested, uint64_t delay) :
+ ZPageCacheFlushClosure(requested),
+ _now(os::elapsedTime()),
+ _delay(delay),
+ _timeout(_delay) {}
+
+ virtual bool do_page(const ZPage* page) {
+ const uint64_t expires = page->last_used() + _delay;
+ const uint64_t timeout = expires - MIN2(expires, _now);
+
+ if (_flushed < _requested && timeout == 0) {
+ // Flush page
+ _flushed += page->size();
+ return true;
+ }
+
+ // Record shortest non-expired timeout
+ _timeout = MIN2(_timeout, timeout);
+
+ // Don't flush page
+ return false;
+ }
+
+ uint64_t timeout() const {
+ return _timeout;
+ }
+};
+
+uint64_t ZPageAllocator::uncommit(uint64_t delay) {
+ // Set the default timeout, when no pages are found in the
+ // cache or when uncommit is disabled, equal to the delay.
+ uint64_t timeout = delay;
+
+ if (!_uncommit) {
+ // Disabled
+ return timeout;
+ }
+
+ size_t capacity_before;
+ size_t capacity_after;
+ size_t uncommitted;
+
+ {
+ SuspendibleThreadSetJoiner joiner;
+ ZLocker<ZLock> locker(&_lock);
+
+ // Don't flush more than we will uncommit. Never uncommit
+ // the reserve, and never uncommit below min capacity.
+ const size_t needed = MIN2(_used + _max_reserve, _current_max_capacity);
+ const size_t guarded = MAX2(needed, _min_capacity);
+ const size_t uncommittable = _capacity - guarded;
+ const size_t uncached_available = _capacity - _used - _cache.available();
+ size_t uncommit = MIN2(uncommittable, uncached_available);
+ const size_t flush = uncommittable - uncommit;
+
+ if (flush > 0) {
+ // Flush pages to uncommit
+ ZPageCacheFlushForUncommitClosure cl(flush, delay);
+ uncommit += flush_cache(&cl);
+ timeout = cl.timeout();
+ }
+
+ // Uncommit
+ uncommitted = _physical.uncommit(uncommit);
+ _capacity -= uncommitted;
+
+ capacity_after = _capacity;
+ capacity_before = capacity_after + uncommitted;
+ }
+
+ if (uncommitted > 0) {
+ log_info(gc, heap)("Capacity: " SIZE_FORMAT "M(%.0lf%%)->" SIZE_FORMAT "M(%.0lf%%), "
+ "Uncommitted: " SIZE_FORMAT "M",
+ capacity_before / M, percent_of(capacity_before, max_capacity()),
+ capacity_after / M, percent_of(capacity_after, max_capacity()),
+ uncommitted / M);
+
+ // Update statistics
+ ZStatInc(ZCounterUncommit, uncommitted);
+ }
+
+ return timeout;
}
void ZPageAllocator::enable_deferred_delete() const {
@@ -525,6 +679,35 @@
_safe_delete.disable_deferred_delete();
}
+void ZPageAllocator::debug_map_page(const ZPage* page) const {
+ assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint");
+ _physical.debug_map(page->physical_memory(), page->start());
+}
+
+class ZPageCacheDebugMapClosure : public StackObj {
+private:
+ const ZPageAllocator* const _allocator;
+
+public:
+ ZPageCacheDebugMapClosure(const ZPageAllocator* allocator) :
+ _allocator(allocator) {}
+
+ virtual void do_page(const ZPage* page) {
+ _allocator->debug_map_page(page);
+ }
+};
+
+void ZPageAllocator::debug_map_cached_pages() const {
+ assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint");
+ ZPageCacheDebugMapClosure cl(this);
+ _cache.pages_do(&cl);
+}
+
+void ZPageAllocator::debug_unmap_all_pages() const {
+ assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint");
+ _physical.debug_unmap(ZPhysicalMemorySegment(0 /* start */, ZAddressOffsetMax), 0 /* offset */);
+}
+
bool ZPageAllocator::is_alloc_stalled() const {
assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint");
return !_queue.is_empty();
--- a/src/hotspot/share/gc/z/zPageAllocator.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zPageAllocator.hpp Wed May 15 13:54:43 2019 +0530
@@ -29,7 +29,6 @@
#include "gc/z/zLock.hpp"
#include "gc/z/zPageCache.hpp"
#include "gc/z/zPhysicalMemory.hpp"
-#include "gc/z/zPreMappedMemory.hpp"
#include "gc/z/zSafeDelete.hpp"
#include "gc/z/zVirtualMemory.hpp"
#include "memory/allocation.hpp"
@@ -44,8 +43,11 @@
ZVirtualMemoryManager _virtual;
ZPhysicalMemoryManager _physical;
ZPageCache _cache;
+ const size_t _min_capacity;
+ const size_t _max_capacity;
const size_t _max_reserve;
- ZPreMappedMemory _pre_mapped;
+ size_t _current_max_capacity;
+ size_t _capacity;
size_t _used_high;
size_t _used_low;
size_t _used;
@@ -53,39 +55,44 @@
ssize_t _reclaimed;
ZList<ZPageAllocRequest> _queue;
mutable ZSafeDelete<ZPage> _safe_delete;
+ bool _uncommit;
+ bool _initialized;
static ZPage* const gc_marker;
+ void prime_cache(size_t size);
+
void increase_used(size_t size, bool relocation);
void decrease_used(size_t size, bool reclaimed);
- size_t max_available(bool no_reserve) const;
- size_t try_ensure_unused(size_t size, bool no_reserve);
- size_t try_ensure_unused_for_pre_mapped(size_t size);
-
ZPage* create_page(uint8_t type, size_t size);
void destroy_page(ZPage* page);
- void flush_pre_mapped();
- void flush_cache(ZPageCacheFlushClosure* cl);
- void evict_cache(size_t requested);
+ size_t max_available(bool no_reserve) const;
+ bool ensure_available(size_t size, bool no_reserve);
+ void ensure_uncached_available(size_t size);
void check_out_of_memory_during_initialization();
- ZPage* alloc_page_common_inner(uint8_t type, size_t size, ZAllocationFlags flags);
+ ZPage* alloc_page_common_inner(uint8_t type, size_t size, bool no_reserve);
ZPage* alloc_page_common(uint8_t type, size_t size, ZAllocationFlags flags);
ZPage* alloc_page_blocking(uint8_t type, size_t size, ZAllocationFlags flags);
ZPage* alloc_page_nonblocking(uint8_t type, size_t size, ZAllocationFlags flags);
+ size_t flush_cache(ZPageCacheFlushClosure* cl);
+ void flush_cache_for_allocation(size_t requested);
+
void satisfy_alloc_queue();
- void detach_memory(const ZVirtualMemory& vmem, ZPhysicalMemory& pmem);
-
public:
- ZPageAllocator(size_t min_capacity, size_t max_capacity, size_t max_reserve);
+ ZPageAllocator(size_t min_capacity,
+ size_t initial_capacity,
+ size_t max_capacity,
+ size_t max_reserve);
bool is_initialized() const;
+ size_t min_capacity() const;
size_t max_capacity() const;
size_t current_max_capacity() const;
size_t capacity() const;
@@ -102,11 +109,16 @@
ZPage* alloc_page(uint8_t type, size_t size, ZAllocationFlags flags);
void free_page(ZPage* page, bool reclaimed);
+ uint64_t uncommit(uint64_t delay);
+
void enable_deferred_delete() const;
void disable_deferred_delete() const;
- void map_page(ZPage* page);
- void unmap_all_pages();
+ void map_page(const ZPage* page) const;
+
+ void debug_map_page(const ZPage* page) const;
+ void debug_map_cached_pages() const;
+ void debug_unmap_all_pages() const;
bool is_alloc_stalled() const;
void check_out_of_memory();
--- a/src/hotspot/share/gc/z/zPageCache.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zPageCache.cpp Wed May 15 13:54:43 2019 +0530
@@ -31,8 +31,17 @@
static const ZStatCounter ZCounterPageCacheHitL1("Memory", "Page Cache Hit L1", ZStatUnitOpsPerSecond);
static const ZStatCounter ZCounterPageCacheHitL2("Memory", "Page Cache Hit L2", ZStatUnitOpsPerSecond);
+static const ZStatCounter ZCounterPageCacheHitL3("Memory", "Page Cache Hit L3", ZStatUnitOpsPerSecond);
static const ZStatCounter ZCounterPageCacheMiss("Memory", "Page Cache Miss", ZStatUnitOpsPerSecond);
+ZPageCacheFlushClosure::ZPageCacheFlushClosure(size_t requested) :
+ _requested(requested),
+ _flushed(0) {}
+
+size_t ZPageCacheFlushClosure::overflushed() const {
+ return _flushed > _requested ? _flushed - _requested : 0;
+}
+
ZPageCache::ZPageCache() :
_available(0),
_small(),
@@ -67,40 +76,73 @@
remote_numa_id++;
}
- ZStatInc(ZCounterPageCacheMiss);
return NULL;
}
ZPage* ZPageCache::alloc_medium_page() {
- ZPage* const l1_page = _medium.remove_first();
- if (l1_page != NULL) {
+ ZPage* const page = _medium.remove_first();
+ if (page != NULL) {
ZStatInc(ZCounterPageCacheHitL1);
- return l1_page;
+ return page;
}
- ZStatInc(ZCounterPageCacheMiss);
return NULL;
}
ZPage* ZPageCache::alloc_large_page(size_t size) {
// Find a page with the right size
ZListIterator<ZPage> iter(&_large);
- for (ZPage* l1_page; iter.next(&l1_page);) {
- if (l1_page->size() == size) {
+ for (ZPage* page; iter.next(&page);) {
+ if (size == page->size()) {
// Page found
- _large.remove(l1_page);
+ _large.remove(page);
ZStatInc(ZCounterPageCacheHitL1);
- return l1_page;
+ return page;
}
}
- ZStatInc(ZCounterPageCacheMiss);
+ return NULL;
+}
+
+ZPage* ZPageCache::alloc_oversized_medium_page(size_t size) {
+ if (size <= ZPageSizeMedium) {
+ return _medium.remove_first();
+ }
+
return NULL;
}
+ZPage* ZPageCache::alloc_oversized_large_page(size_t size) {
+ // Find a page that is large enough
+ ZListIterator<ZPage> iter(&_large);
+ for (ZPage* page; iter.next(&page);) {
+ if (size <= page->size()) {
+ // Page found
+ _large.remove(page);
+ return page;
+ }
+ }
+
+ return NULL;
+}
+
+ZPage* ZPageCache::alloc_oversized_page(size_t size) {
+ ZPage* page = alloc_oversized_large_page(size);
+ if (page == NULL) {
+ page = alloc_oversized_medium_page(size);
+ }
+
+ if (page != NULL) {
+ ZStatInc(ZCounterPageCacheHitL3);
+ }
+
+ return page;
+}
+
ZPage* ZPageCache::alloc_page(uint8_t type, size_t size) {
ZPage* page;
+ // Try allocate exact page
if (type == ZPageTypeSmall) {
page = alloc_small_page();
} else if (type == ZPageTypeMedium) {
@@ -109,14 +151,33 @@
page = alloc_large_page(size);
}
+ if (page == NULL) {
+ // Try allocate potentially oversized page
+ ZPage* const oversized = alloc_oversized_page(size);
+ if (oversized != NULL) {
+ if (size < oversized->size()) {
+ // Split oversized page
+ page = oversized->split(type, size);
+
+ // Cache remainder
+ free_page_inner(oversized);
+ } else {
+ // Re-type correctly sized page
+ page = oversized->retype(type);
+ }
+ }
+ }
+
if (page != NULL) {
_available -= page->size();
+ } else {
+ ZStatInc(ZCounterPageCacheMiss);
}
return page;
}
-void ZPageCache::free_page(ZPage* page) {
+void ZPageCache::free_page_inner(ZPage* page) {
const uint8_t type = page->type();
if (type == ZPageTypeSmall) {
_small.get(page->numa_id()).insert_first(page);
@@ -125,7 +186,10 @@
} else {
_large.insert_first(page);
}
+}
+void ZPageCache::free_page(ZPage* page) {
+ free_page_inner(page);
_available += page->size();
}
--- a/src/hotspot/share/gc/z/zPageCache.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zPageCache.hpp Wed May 15 13:54:43 2019 +0530
@@ -30,7 +30,13 @@
#include "memory/allocation.hpp"
class ZPageCacheFlushClosure : public StackObj {
+protected:
+ const size_t _requested;
+ size_t _flushed;
+
public:
+ ZPageCacheFlushClosure(size_t requested);
+ size_t overflushed() const;
virtual bool do_page(const ZPage* page) = 0;
};
@@ -45,6 +51,12 @@
ZPage* alloc_medium_page();
ZPage* alloc_large_page(size_t size);
+ ZPage* alloc_oversized_medium_page(size_t size);
+ ZPage* alloc_oversized_large_page(size_t size);
+ ZPage* alloc_oversized_page(size_t size);
+
+ void free_page_inner(ZPage* page);
+
bool flush_list_inner(ZPageCacheFlushClosure* cl, ZList<ZPage>* from, ZList<ZPage>* to);
void flush_list(ZPageCacheFlushClosure* cl, ZList<ZPage>* from, ZList<ZPage>* to);
void flush_per_numa_lists(ZPageCacheFlushClosure* cl, ZPerNUMA<ZList<ZPage> >* from, ZList<ZPage>* to);
@@ -58,6 +70,8 @@
void free_page(ZPage* page);
void flush(ZPageCacheFlushClosure* cl, ZList<ZPage>* to);
+
+ template <typename Closure> void pages_do(Closure* cl) const;
};
#endif // SHARE_GC_Z_ZPAGECACHE_HPP
--- a/src/hotspot/share/gc/z/zPageCache.inline.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zPageCache.inline.hpp Wed May 15 13:54:43 2019 +0530
@@ -24,10 +24,35 @@
#ifndef SHARE_GC_Z_ZPAGECACHE_INLINE_HPP
#define SHARE_GC_Z_ZPAGECACHE_INLINE_HPP
+#include "gc/z/zList.inline.hpp"
#include "gc/z/zPageCache.hpp"
inline size_t ZPageCache::available() const {
return _available;
}
+template <typename Closure>
+inline void ZPageCache::pages_do(Closure* cl) const {
+ // Small
+ ZPerNUMAConstIterator<ZList<ZPage> > iter_numa(&_small);
+ for (const ZList<ZPage>* list; iter_numa.next(&list);) {
+ ZListIterator<ZPage> iter_small(list);
+ for (ZPage* page; iter_small.next(&page);) {
+ cl->do_page(page);
+ }
+ }
+
+ // Medium
+ ZListIterator<ZPage> iter_medium(&_medium);
+ for (ZPage* page; iter_medium.next(&page);) {
+ cl->do_page(page);
+ }
+
+ // Large
+ ZListIterator<ZPage> iter_large(&_large);
+ for (ZPage* page; iter_large.next(&page);) {
+ cl->do_page(page);
+ }
+}
+
#endif // SHARE_GC_Z_ZPAGECACHE_INLINE_HPP
--- a/src/hotspot/share/gc/z/zPhysicalMemory.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zPhysicalMemory.cpp Wed May 15 13:54:43 2019 +0530
@@ -33,18 +33,42 @@
_nsegments(0),
_segments(NULL) {}
-ZPhysicalMemory::ZPhysicalMemory(size_t size) :
- _nsegments(0),
- _segments(NULL) {
- add_segment(ZPhysicalMemorySegment(0, size));
-}
-
ZPhysicalMemory::ZPhysicalMemory(const ZPhysicalMemorySegment& segment) :
_nsegments(0),
_segments(NULL) {
add_segment(segment);
}
+ZPhysicalMemory::ZPhysicalMemory(const ZPhysicalMemory& pmem) :
+ _nsegments(0),
+ _segments(NULL) {
+
+ // Copy segments
+ for (size_t i = 0; i < pmem.nsegments(); i++) {
+ add_segment(pmem.segment(i));
+ }
+}
+
+const ZPhysicalMemory& ZPhysicalMemory::operator=(const ZPhysicalMemory& pmem) {
+ // Free segments
+ delete [] _segments;
+ _segments = NULL;
+ _nsegments = 0;
+
+ // Copy segments
+ for (size_t i = 0; i < pmem.nsegments(); i++) {
+ add_segment(pmem.segment(i));
+ }
+
+ return *this;
+}
+
+ZPhysicalMemory::~ZPhysicalMemory() {
+ delete [] _segments;
+ _segments = NULL;
+ _nsegments = 0;
+}
+
size_t ZPhysicalMemory::size() const {
size_t size = 0;
@@ -55,134 +79,114 @@
return size;
}
-void ZPhysicalMemory::add_segment(ZPhysicalMemorySegment segment) {
+void ZPhysicalMemory::add_segment(const ZPhysicalMemorySegment& segment) {
// Try merge with last segment
if (_nsegments > 0) {
ZPhysicalMemorySegment& last = _segments[_nsegments - 1];
assert(last.end() <= segment.start(), "Segments added out of order");
if (last.end() == segment.start()) {
- // Merge
- last.expand(segment.size());
+ last = ZPhysicalMemorySegment(last.start(), last.size() + segment.size());
return;
}
}
- // Make room for a new segment
- const size_t size = sizeof(ZPhysicalMemorySegment) * (_nsegments + 1);
- _segments = (ZPhysicalMemorySegment*)ReallocateHeap((char*)_segments, size, mtGC);
+ // Resize array
+ ZPhysicalMemorySegment* const old_segments = _segments;
+ _segments = new ZPhysicalMemorySegment[_nsegments + 1];
+ for (size_t i = 0; i < _nsegments; i++) {
+ _segments[i] = old_segments[i];
+ }
+ delete [] old_segments;
// Add new segment
_segments[_nsegments] = segment;
_nsegments++;
}
-ZPhysicalMemory ZPhysicalMemory::split(size_t split_size) {
- // Only splitting of single-segment instances have been implemented.
- assert(nsegments() == 1, "Can only have one segment");
- assert(split_size <= size(), "Invalid size");
- return ZPhysicalMemory(_segments[0].split(split_size));
-}
+ZPhysicalMemory ZPhysicalMemory::split(size_t size) {
+ ZPhysicalMemory pmem;
+ size_t nsegments = 0;
-void ZPhysicalMemory::clear() {
- if (_segments != NULL) {
- FreeHeap(_segments);
- _segments = NULL;
- _nsegments = 0;
+ for (size_t i = 0; i < _nsegments; i++) {
+ const ZPhysicalMemorySegment& segment = _segments[i];
+ if (pmem.size() < size) {
+ if (pmem.size() + segment.size() <= size) {
+ // Transfer segment
+ pmem.add_segment(segment);
+ } else {
+ // Split segment
+ const size_t split_size = size - pmem.size();
+ pmem.add_segment(ZPhysicalMemorySegment(segment.start(), split_size));
+ _segments[nsegments++] = ZPhysicalMemorySegment(segment.start() + split_size, segment.size() - split_size);
+ }
+ } else {
+ // Keep segment
+ _segments[nsegments++] = segment;
+ }
}
+
+ _nsegments = nsegments;
+
+ return pmem;
}
-ZPhysicalMemoryManager::ZPhysicalMemoryManager(size_t max_capacity) :
- _backing(max_capacity),
- _max_capacity(max_capacity),
- _current_max_capacity(max_capacity),
- _capacity(0),
- _used(0) {}
-
bool ZPhysicalMemoryManager::is_initialized() const {
return _backing.is_initialized();
}
-void ZPhysicalMemoryManager::try_ensure_unused_capacity(size_t size) {
- const size_t unused = unused_capacity();
- if (unused >= size) {
- // Don't try to expand, enough unused capacity available
- return;
- }
-
- const size_t current_max = current_max_capacity();
- if (_capacity == current_max) {
- // Don't try to expand, current max capacity reached
- return;
- }
-
- // Try to expand
- const size_t old_capacity = capacity();
- const size_t new_capacity = MIN2(old_capacity + size - unused, current_max);
- _capacity = _backing.try_expand(old_capacity, new_capacity);
-
- if (_capacity != new_capacity) {
- // Failed, or partly failed, to expand
- log_error(gc, init)("Not enough space available on the backing filesystem to hold the current max");
- log_error(gc, init)("Java heap size (" SIZE_FORMAT "M). Forcefully lowering max Java heap size to "
- SIZE_FORMAT "M (%.0lf%%).", current_max / M, _capacity / M,
- percent_of(_capacity, current_max));
-
- // Adjust current max capacity to avoid further expand attempts
- _current_max_capacity = _capacity;
- }
+void ZPhysicalMemoryManager::warn_commit_limits(size_t max) const {
+ _backing.warn_commit_limits(max);
}
-void ZPhysicalMemoryManager::nmt_commit(ZPhysicalMemory pmem, uintptr_t offset) {
+bool ZPhysicalMemoryManager::supports_uncommit() {
+ return _backing.supports_uncommit();
+}
+
+void ZPhysicalMemoryManager::nmt_commit(const ZPhysicalMemory& pmem, uintptr_t offset) const {
const uintptr_t addr = _backing.nmt_address(offset);
const size_t size = pmem.size();
MemTracker::record_virtual_memory_commit((void*)addr, size, CALLER_PC);
}
-void ZPhysicalMemoryManager::nmt_uncommit(ZPhysicalMemory pmem, uintptr_t offset) {
+void ZPhysicalMemoryManager::nmt_uncommit(const ZPhysicalMemory& pmem, uintptr_t offset) const {
if (MemTracker::tracking_level() > NMT_minimal) {
const uintptr_t addr = _backing.nmt_address(offset);
const size_t size = pmem.size();
-
Tracker tracker(Tracker::uncommit);
tracker.record((address)addr, size);
}
}
+size_t ZPhysicalMemoryManager::commit(size_t size) {
+ return _backing.commit(size);
+}
+
+size_t ZPhysicalMemoryManager::uncommit(size_t size) {
+ return _backing.uncommit(size);
+}
+
ZPhysicalMemory ZPhysicalMemoryManager::alloc(size_t size) {
- if (unused_capacity() < size) {
- // Not enough memory available
- return ZPhysicalMemory();
- }
-
- _used += size;
return _backing.alloc(size);
}
-void ZPhysicalMemoryManager::free(ZPhysicalMemory pmem) {
+void ZPhysicalMemoryManager::free(const ZPhysicalMemory& pmem) {
_backing.free(pmem);
- _used -= pmem.size();
}
-void ZPhysicalMemoryManager::map(ZPhysicalMemory pmem, uintptr_t offset) {
- // Map page
+void ZPhysicalMemoryManager::map(const ZPhysicalMemory& pmem, uintptr_t offset) const {
_backing.map(pmem, offset);
-
- // Update native memory tracker
nmt_commit(pmem, offset);
}
-void ZPhysicalMemoryManager::unmap(ZPhysicalMemory pmem, uintptr_t offset) {
- // Update native memory tracker
+void ZPhysicalMemoryManager::unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const {
nmt_uncommit(pmem, offset);
-
- // Unmap page
_backing.unmap(pmem, offset);
}
-void ZPhysicalMemoryManager::debug_map(ZPhysicalMemory pmem, uintptr_t offset) {
+void ZPhysicalMemoryManager::debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const {
_backing.debug_map(pmem, offset);
}
-void ZPhysicalMemoryManager::debug_unmap(ZPhysicalMemory pmem, uintptr_t offset) {
+void ZPhysicalMemoryManager::debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const {
_backing.debug_unmap(pmem, offset);
}
--- a/src/hotspot/share/gc/z/zPhysicalMemory.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zPhysicalMemory.hpp Wed May 15 13:54:43 2019 +0530
@@ -27,20 +27,18 @@
#include "memory/allocation.hpp"
#include OS_CPU_HEADER(gc/z/zPhysicalMemoryBacking)
-class ZPhysicalMemorySegment {
+class ZPhysicalMemorySegment : public CHeapObj<mtGC> {
private:
uintptr_t _start;
uintptr_t _end;
public:
+ ZPhysicalMemorySegment();
ZPhysicalMemorySegment(uintptr_t start, size_t size);
uintptr_t start() const;
uintptr_t end() const;
size_t size() const;
-
- void expand(size_t size);
- ZPhysicalMemorySegment split(size_t size);
};
class ZPhysicalMemory {
@@ -50,53 +48,45 @@
public:
ZPhysicalMemory();
- ZPhysicalMemory(size_t size);
ZPhysicalMemory(const ZPhysicalMemorySegment& segment);
+ ZPhysicalMemory(const ZPhysicalMemory& pmem);
+ const ZPhysicalMemory& operator=(const ZPhysicalMemory& pmem);
+ ~ZPhysicalMemory();
bool is_null() const;
size_t size() const;
size_t nsegments() const;
- ZPhysicalMemorySegment segment(size_t index) const;
- void add_segment(ZPhysicalMemorySegment segment);
+ const ZPhysicalMemorySegment& segment(size_t index) const;
+ void add_segment(const ZPhysicalMemorySegment& segment);
ZPhysicalMemory split(size_t size);
- void clear();
};
class ZPhysicalMemoryManager {
- friend class VMStructs;
-
private:
ZPhysicalMemoryBacking _backing;
- const size_t _max_capacity;
- size_t _current_max_capacity;
- size_t _capacity;
- size_t _used;
- void nmt_commit(ZPhysicalMemory pmem, uintptr_t offset);
- void nmt_uncommit(ZPhysicalMemory pmem, uintptr_t offset);
+ void nmt_commit(const ZPhysicalMemory& pmem, uintptr_t offset) const;
+ void nmt_uncommit(const ZPhysicalMemory& pmem, uintptr_t offset) const;
public:
- ZPhysicalMemoryManager(size_t max_capacity);
-
bool is_initialized() const;
- size_t max_capacity() const;
- size_t current_max_capacity() const;
- size_t capacity() const;
- size_t unused_capacity() const;
+ void warn_commit_limits(size_t max) const;
+ bool supports_uncommit();
- void try_ensure_unused_capacity(size_t size);
+ size_t commit(size_t size);
+ size_t uncommit(size_t size);
ZPhysicalMemory alloc(size_t size);
- void free(ZPhysicalMemory pmem);
+ void free(const ZPhysicalMemory& pmem);
- void map(ZPhysicalMemory pmem, uintptr_t offset);
- void unmap(ZPhysicalMemory pmem, uintptr_t offset);
+ void map(const ZPhysicalMemory& pmem, uintptr_t offset) const;
+ void unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const;
- void debug_map(ZPhysicalMemory pmem, uintptr_t offset);
- void debug_unmap(ZPhysicalMemory pmem, uintptr_t offset);
+ void debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const;
+ void debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const;
};
#endif // SHARE_GC_Z_ZPHYSICALMEMORY_HPP
--- a/src/hotspot/share/gc/z/zPhysicalMemory.inline.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zPhysicalMemory.inline.hpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -27,6 +27,10 @@
#include "gc/z/zPhysicalMemory.hpp"
#include "utilities/debug.hpp"
+inline ZPhysicalMemorySegment::ZPhysicalMemorySegment() :
+ _start(UINTPTR_MAX),
+ _end(UINTPTR_MAX) {}
+
inline ZPhysicalMemorySegment::ZPhysicalMemorySegment(uintptr_t start, size_t size) :
_start(start),
_end(start + size) {}
@@ -40,18 +44,7 @@
}
inline size_t ZPhysicalMemorySegment::size() const {
- return end() - start();
-}
-
-inline void ZPhysicalMemorySegment::expand(size_t size) {
- _end += size;
-}
-
-inline ZPhysicalMemorySegment ZPhysicalMemorySegment::split(size_t split_size) {
- assert(split_size <= size(), "Invalid size");
- ZPhysicalMemorySegment segment(_start, split_size);
- _start += split_size;
- return segment;
+ return _end - _start;
}
inline bool ZPhysicalMemory::is_null() const {
@@ -62,25 +55,9 @@
return _nsegments;
}
-inline ZPhysicalMemorySegment ZPhysicalMemory::segment(size_t index) const {
+inline const ZPhysicalMemorySegment& ZPhysicalMemory::segment(size_t index) const {
assert(index < _nsegments, "Invalid segment index");
return _segments[index];
}
-inline size_t ZPhysicalMemoryManager::max_capacity() const {
- return _max_capacity;
-}
-
-inline size_t ZPhysicalMemoryManager::current_max_capacity() const {
- return _current_max_capacity;
-}
-
-inline size_t ZPhysicalMemoryManager::capacity() const {
- return _capacity;
-}
-
-inline size_t ZPhysicalMemoryManager::unused_capacity() const {
- return _capacity - _used;
-}
-
#endif // SHARE_GC_Z_ZPHYSICALMEMORY_INLINE_HPP
--- a/src/hotspot/share/gc/z/zPreMappedMemory.cpp Tue May 14 11:23:08 2019 +0530
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "precompiled.hpp"
-#include "gc/z/zPage.inline.hpp"
-#include "gc/z/zPhysicalMemory.inline.hpp"
-#include "gc/z/zPreMappedMemory.inline.hpp"
-#include "gc/z/zVirtualMemory.inline.hpp"
-#include "logging/log.hpp"
-
-ZPreMappedMemory::ZPreMappedMemory(ZVirtualMemoryManager &vmm, ZPhysicalMemoryManager &pmm, size_t size) :
- _vmem(),
- _pmem(),
- _initialized(false) {
- if (!vmm.is_initialized() || !pmm.is_initialized()) {
- // Not initialized
- return;
- }
-
- // Pre-mapping and pre-touching memory can take a long time. Log a message
- // to help the user understand why the JVM might seem slow to start.
- log_info(gc, init)("Pre-touching: %s", AlwaysPreTouch ? "Enabled" : "Disabled");
- log_info(gc, init)("Pre-mapping: " SIZE_FORMAT "M", size / M);
-
- if (size > 0) {
- _pmem = pmm.alloc(size);
- if (_pmem.is_null()) {
- // Out of memory
- log_error(gc, init)("Failed to pre-map Java heap (Cannot allocate physical memory)");
- return;
- }
-
- _vmem = vmm.alloc(size, true /* alloc_from_front */);
- if (_vmem.is_null()) {
- // Out of address space
- log_error(gc, init)("Failed to pre-map Java heap (Cannot allocate virtual memory)");
- pmm.free(_pmem);
- return;
- }
-
- // Map physical memory
- pmm.map(_pmem, _vmem.start());
- }
-
- _initialized = true;
-}
-
-ZPage* ZPreMappedMemory::alloc_page(uint8_t type, size_t size) {
- if (size > available()) {
- // Not enough pre-mapped memory
- return NULL;
- }
-
- // Take a chunk of the pre-mapped memory
- const ZPhysicalMemory pmem = _pmem.split(size);
- const ZVirtualMemory vmem = _vmem.split(size);
-
- ZPage* const page = new ZPage(type, vmem, pmem);
- page->set_pre_mapped();
-
- return page;
-}
-
-void ZPreMappedMemory::clear() {
- assert(_pmem.is_null(), "Should be detached");
- _vmem.clear();
-}
--- a/src/hotspot/share/gc/z/zPreMappedMemory.hpp Tue May 14 11:23:08 2019 +0530
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#ifndef SHARE_GC_Z_ZPREMAPPEDMEMORY_HPP
-#define SHARE_GC_Z_ZPREMAPPEDMEMORY_HPP
-
-#include "gc/z/zPhysicalMemory.hpp"
-#include "gc/z/zVirtualMemory.hpp"
-#include "memory/allocation.hpp"
-
-class ZPage;
-
-class ZPreMappedMemory {
-private:
- ZVirtualMemory _vmem;
- ZPhysicalMemory _pmem;
- bool _initialized;
-
-public:
- ZPreMappedMemory(ZVirtualMemoryManager &vmm, ZPhysicalMemoryManager &pmm, size_t size);
-
- bool is_initialized() const;
-
- ZPhysicalMemory& physical_memory();
- const ZVirtualMemory& virtual_memory() const;
-
- size_t available() const;
-
- ZPage* alloc_page(uint8_t type, size_t size);
-
- void clear();
-};
-
-#endif // SHARE_GC_Z_ZPREMAPPEDMEMORY_HPP
--- a/src/hotspot/share/gc/z/zPreMappedMemory.inline.hpp Tue May 14 11:23:08 2019 +0530
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#ifndef SHARE_GC_Z_ZPREMAPPEDMEMORY_INLINE_HPP
-#define SHARE_GC_Z_ZPREMAPPEDMEMORY_INLINE_HPP
-
-#include "gc/z/zPreMappedMemory.hpp"
-
-inline bool ZPreMappedMemory::is_initialized() const {
- return _initialized;
-}
-
-inline ZPhysicalMemory& ZPreMappedMemory::physical_memory() {
- return _pmem;
-}
-
-inline const ZVirtualMemory& ZPreMappedMemory::virtual_memory() const {
- return _vmem;
-}
-
-inline size_t ZPreMappedMemory::available() const {
- return _vmem.size();
-}
-
-#endif // SHARE_GC_Z_ZPREMAPPEDMEMORY_INLINE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/z/zUncommitter.cpp Wed May 15 13:54:43 2019 +0530
@@ -0,0 +1,74 @@
+/*
+ * 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 "precompiled.hpp"
+#include "gc/z/zHeap.inline.hpp"
+#include "gc/z/zUncommitter.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/os.hpp"
+
+ZUncommitter::ZUncommitter() :
+ _monitor(Monitor::leaf, "ZUncommitter", false, Monitor::_safepoint_check_never),
+ _stop(false) {
+ set_name("ZUncommitter");
+ create_and_start();
+}
+
+bool ZUncommitter::idle(uint64_t timeout) {
+ // Idle for at least one second
+ const uint64_t expires = os::elapsedTime() + MAX2(timeout, 1ul);
+
+ for (;;) {
+ // We might wake up spuriously from wait, so always recalculate
+ // the timeout after a wakeup to see if we need to wait again.
+ const uint64_t now = os::elapsedTime();
+ const uint64_t remaining = expires - MIN2(expires, now);
+
+ MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag);
+ if (remaining > 0 && !_stop) {
+ ml.wait(remaining * MILLIUNITS);
+ } else {
+ return !_stop;
+ }
+ }
+}
+
+void ZUncommitter::run_service() {
+ for (;;) {
+ // Try uncommit unused memory
+ const uint64_t timeout = ZHeap::heap()->uncommit(ZUncommitDelay);
+
+ log_trace(gc, heap)("Uncommit Timeout: " UINT64_FORMAT "s", timeout);
+
+ // Idle until next attempt
+ if (!idle(timeout)) {
+ return;
+ }
+ }
+}
+
+void ZUncommitter::stop_service() {
+ MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag);
+ _stop = true;
+ ml.notify();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/z/zUncommitter.hpp Wed May 15 13:54:43 2019 +0530
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef SHARE_GC_Z_ZUNCOMMITTER_HPP
+#define SHARE_GC_Z_ZUNCOMMITTER_HPP
+
+#include "gc/shared/concurrentGCThread.hpp"
+#include "runtime/mutex.hpp"
+
+class ZUncommitter : public ConcurrentGCThread {
+private:
+ Monitor _monitor;
+ bool _stop;
+
+ bool idle(uint64_t timeout);
+
+protected:
+ virtual void run_service();
+ virtual void stop_service();
+
+public:
+ ZUncommitter();
+};
+
+#endif // SHARE_GC_Z_ZUNCOMMITTER_HPP
--- a/src/hotspot/share/gc/z/zVirtualMemory.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zVirtualMemory.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -72,6 +72,6 @@
return ZVirtualMemory(start, size);
}
-void ZVirtualMemoryManager::free(ZVirtualMemory vmem) {
+void ZVirtualMemoryManager::free(const ZVirtualMemory& vmem) {
_manager.free(vmem.start(), vmem.size());
}
--- a/src/hotspot/share/gc/z/zVirtualMemory.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zVirtualMemory.hpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -25,7 +25,6 @@
#define SHARE_GC_Z_ZVIRTUALMEMORY_HPP
#include "gc/z/zMemory.hpp"
-#include "memory/allocation.hpp"
class ZVirtualMemory {
friend class VMStructs;
@@ -42,8 +41,8 @@
uintptr_t start() const;
uintptr_t end() const;
size_t size() const;
+
ZVirtualMemory split(size_t size);
- void clear();
};
class ZVirtualMemoryManager {
@@ -60,7 +59,7 @@
bool is_initialized() const;
ZVirtualMemory alloc(size_t size, bool alloc_from_front = false);
- void free(ZVirtualMemory vmem);
+ void free(const ZVirtualMemory& vmem);
};
#endif // SHARE_GC_Z_ZVIRTUALMEMORY_HPP
--- a/src/hotspot/share/gc/z/zVirtualMemory.inline.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/zVirtualMemory.inline.hpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -51,16 +51,9 @@
return _end - _start;
}
-inline ZVirtualMemory ZVirtualMemory::split(size_t split_size) {
- assert(split_size <= size(), "precondition");
- ZVirtualMemory mem(_start, split_size);
- _start += split_size;
- return mem;
-}
-
-inline void ZVirtualMemory::clear() {
- _start = UINTPTR_MAX;
- _end = UINTPTR_MAX;
+inline ZVirtualMemory ZVirtualMemory::split(size_t size) {
+ _start += size;
+ return ZVirtualMemory(_start - size, size);
}
#endif // SHARE_GC_Z_ZVIRTUALMEMORY_INLINE_HPP
--- a/src/hotspot/share/gc/z/z_globals.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/gc/z/z_globals.hpp Wed May 15 13:54:43 2019 +0530
@@ -56,6 +56,13 @@
experimental(uint, ZCollectionInterval, 0, \
"Force GC at a fixed time interval (in seconds)") \
\
+ experimental(bool, ZUncommit, true, \
+ "Uncommit unused memory") \
+ \
+ experimental(uintx, ZUncommitDelay, 5 * 60, \
+ "Uncommit memory if it has been unused for the specified " \
+ "amount of time (in seconds)") \
+ \
diagnostic(uint, ZStatisticsInterval, 10, \
"Time between statistics print outs (in seconds)") \
range(1, (uint)-1) \
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp Wed May 15 13:54:43 2019 +0530
@@ -417,7 +417,7 @@
JRT_ENTRY(void, InterpreterRuntime::create_exception(JavaThread* thread, char* name, char* message))
// lookup exception klass
- TempNewSymbol s = SymbolTable::new_symbol(name, CHECK);
+ TempNewSymbol s = SymbolTable::new_symbol(name);
if (ProfileTraps) {
if (s == vmSymbols::java_lang_ArithmeticException()) {
note_trap(thread, Deoptimization::Reason_div0_check, CHECK);
@@ -436,7 +436,7 @@
ResourceMark rm(thread);
const char* klass_name = obj->klass()->external_name();
// lookup exception klass
- TempNewSymbol s = SymbolTable::new_symbol(name, CHECK);
+ TempNewSymbol s = SymbolTable::new_symbol(name);
if (ProfileTraps) {
note_trap(thread, Deoptimization::Reason_class_check, CHECK);
}
--- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -171,8 +171,8 @@
assert(args != NULL, "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
assert(args->klass() != NULL, "invariant");
- args->set_name("<init>", CHECK_NULL);
- args->set_signature("()V", CHECK_NULL);
+ args->set_name("<init>");
+ args->set_signature("()V");
JfrJavaSupport::new_object(args, CHECK_NULL);
return (oop)args->result()->get_jobject();
}
--- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, 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
@@ -357,7 +357,6 @@
}
};
-static unsigned int unused_hash = 0;
static const char value_name[] = "value";
static bool has_annotation(const InstanceKlass* ik, const Symbol* annotation_type, bool& value) {
assert(annotation_type != NULL, "invariant");
@@ -372,7 +371,7 @@
if (annotation_iterator.type() == annotation_type) {
// target annotation found
static const Symbol* value_symbol =
- SymbolTable::lookup_only(value_name, sizeof value_name - 1, unused_hash);
+ SymbolTable::probe(value_name, sizeof value_name - 1);
assert(value_symbol != NULL, "invariant");
const AnnotationElementIterator element_iterator = annotation_iterator.elements();
while (element_iterator.has_next()) {
@@ -412,7 +411,7 @@
}
static Symbol* jdk_jfr_module_symbol = NULL;
if (jdk_jfr_module_symbol == NULL) {
- jdk_jfr_module_symbol = SymbolTable::lookup_only(jdk_jfr_module_name, sizeof jdk_jfr_module_name - 1, unused_hash);
+ jdk_jfr_module_symbol = SymbolTable::probe(jdk_jfr_module_name, sizeof jdk_jfr_module_name - 1);
if (jdk_jfr_module_symbol == NULL) {
return false;
}
@@ -447,7 +446,7 @@
assert(!untypedEventHandler, "invariant");
static const Symbol* registered_symbol = NULL;
if (registered_symbol == NULL) {
- registered_symbol = SymbolTable::lookup_only(registered_constant, sizeof registered_constant - 1, unused_hash);
+ registered_symbol = SymbolTable::probe(registered_constant, sizeof registered_constant - 1);
if (registered_symbol == NULL) {
untypedEventHandler = true;
return false;
@@ -1167,7 +1166,7 @@
u2& added_cp_entries,
TRAPS) {
assert(utf8_constant != NULL, "invariant");
- TempNewSymbol utf8_sym = SymbolTable::new_symbol(utf8_constant, THREAD);
+ TempNewSymbol utf8_sym = SymbolTable::new_symbol(utf8_constant);
// lookup existing
const int utf8_orig_idx = utf8_info_index(ik, utf8_sym, THREAD);
if (utf8_orig_idx != invalid_cp_index) {
--- a/src/hotspot/share/jfr/jni/jfrGetAllEventClasses.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jfr/jni/jfrGetAllEventClasses.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, 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
@@ -134,8 +134,7 @@
initialize(THREAD);
assert(empty_java_util_arraylist != NULL, "should have been setup already!");
static const char jdk_jfr_event_name[] = "jdk/internal/event/Event";
- unsigned int unused_hash = 0;
- Symbol* const event_klass_name = SymbolTable::lookup_only(jdk_jfr_event_name, sizeof jdk_jfr_event_name - 1, unused_hash);
+ Symbol* const event_klass_name = SymbolTable::probe(jdk_jfr_event_name, sizeof jdk_jfr_event_name - 1);
if (NULL == event_klass_name) {
// not loaded yet
@@ -168,10 +167,10 @@
const Klass* const array_list_klass = JfrJavaSupport::klass(empty_java_util_arraylist);
assert(array_list_klass != NULL, "invariant");
- const Symbol* const add_method_sym = SymbolTable::lookup(add_method_name, sizeof add_method_name - 1, THREAD);
+ const Symbol* const add_method_sym = SymbolTable::new_symbol(add_method_name);
assert(add_method_sym != NULL, "invariant");
- const Symbol* const add_method_sig_sym = SymbolTable::lookup(add_method_signature, sizeof add_method_signature - 1, THREAD);
+ const Symbol* const add_method_sig_sym = SymbolTable::new_symbol(add_method_signature);
assert(add_method_signature != NULL, "invariant");
JavaValue result(T_BOOLEAN);
--- a/src/hotspot/share/jfr/jni/jfrJavaCall.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jfr/jni/jfrJavaCall.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -38,9 +38,9 @@
}
#endif // ASSERT
-static Symbol* resolve(const char* str, TRAPS) {
+static Symbol* resolve(const char* str) {
assert(str != NULL, "invariant");
- return SymbolTable::lookup(str, (int)strlen(str), THREAD);
+ return SymbolTable::new_symbol(str);
}
static Klass* resolve(Symbol* k_sym, TRAPS) {
@@ -199,10 +199,10 @@
set_klass(klass_name, CHECK);
}
if (name != NULL) {
- set_name(name, CHECK);
+ set_name(name);
}
if (signature != NULL) {
- set_signature(signature, THREAD);
+ set_signature(signature);
}
}
@@ -230,7 +230,7 @@
void JfrJavaArguments::set_klass(const char* klass_name, TRAPS) {
assert(klass_name != NULL, "invariant");
- Symbol* const k_sym = resolve(klass_name, CHECK);
+ Symbol* const k_sym = resolve(klass_name);
assert(k_sym != NULL, "invariant");
const Klass* const klass = resolve(k_sym, CHECK);
set_klass(klass);
@@ -246,9 +246,9 @@
return const_cast<Symbol*>(_name);
}
-void JfrJavaArguments::set_name(const char* name, TRAPS) {
+void JfrJavaArguments::set_name(const char* name) {
assert(name != NULL, "invariant");
- const Symbol* const sym = resolve(name, CHECK);
+ const Symbol* const sym = resolve(name);
set_name(sym);
}
@@ -262,9 +262,9 @@
return const_cast<Symbol*>(_signature);
}
-void JfrJavaArguments::set_signature(const char* signature, TRAPS) {
+void JfrJavaArguments::set_signature(const char* signature) {
assert(signature != NULL, "invariant");
- const Symbol* const sym = resolve(signature, CHECK);
+ const Symbol* const sym = resolve(signature);
set_signature(sym);
}
--- a/src/hotspot/share/jfr/jni/jfrJavaCall.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jfr/jni/jfrJavaCall.hpp Wed May 15 13:54:43 2019 +0530
@@ -47,11 +47,11 @@
void set_klass(const Klass* klass);
Symbol* name() const;
- void set_name(const char* name, TRAPS);
+ void set_name(const char* name);
void set_name(const Symbol* name);
Symbol* signature() const;
- void set_signature(const char* signature, TRAPS);
+ void set_signature(const char* signature);
void set_signature(const Symbol* signature);
int array_length() const;
--- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp Wed May 15 13:54:43 2019 +0530
@@ -579,7 +579,7 @@
static bool is_jdk_jfr_module_in_readability_graph() {
Thread* const t = Thread::current();
// take one of the packages in the module to be located and query for its definition.
- TempNewSymbol pkg_sym = SymbolTable::new_symbol(JDK_JFR_PACKAGE_NAME, t);
+ TempNewSymbol pkg_sym = SymbolTable::new_symbol(JDK_JFR_PACKAGE_NAME);
return Modules::is_package_defined(pkg_sym, Handle(), t);
}
--- a/src/hotspot/share/jfr/jni/jfrUpcalls.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jfr/jni/jfrUpcalls.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, 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
@@ -49,11 +49,11 @@
static bool initialized = false;
if (!initialized) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
- jvm_upcalls_class_sym = SymbolTable::new_permanent_symbol("jdk/jfr/internal/JVMUpcalls", CHECK_false);
- on_retransform_method_sym = SymbolTable::new_permanent_symbol("onRetransform", CHECK_false);
- on_retransform_signature_sym = SymbolTable::new_permanent_symbol("(JZLjava/lang/Class;[B)[B", CHECK_false);
- bytes_for_eager_instrumentation_sym = SymbolTable::new_permanent_symbol("bytesForEagerInstrumentation", CHECK_false);
- bytes_for_eager_instrumentation_sig_sym = SymbolTable::new_permanent_symbol("(JZLjava/lang/Class;[B)[B", THREAD);
+ jvm_upcalls_class_sym = SymbolTable::new_permanent_symbol("jdk/jfr/internal/JVMUpcalls");
+ on_retransform_method_sym = SymbolTable::new_permanent_symbol("onRetransform");
+ on_retransform_signature_sym = SymbolTable::new_permanent_symbol("(JZLjava/lang/Class;[B)[B");
+ bytes_for_eager_instrumentation_sym = SymbolTable::new_permanent_symbol("bytesForEagerInstrumentation");
+ bytes_for_eager_instrumentation_sig_sym = SymbolTable::new_permanent_symbol("(JZLjava/lang/Class;[B)[B");
initialized = bytes_for_eager_instrumentation_sig_sym != NULL;
}
return initialized;
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleDescription.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleDescription.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -91,7 +91,7 @@
void ObjectSampleDescription::ensure_initialized() {
if (symbol_size == NULL) {
- symbol_size = SymbolTable::new_permanent_symbol("size", Thread::current());
+ symbol_size = SymbolTable::new_permanent_symbol("size");
}
}
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -87,14 +87,14 @@
static const Symbol* jdk_internal_event_sym = NULL;
if (jdk_internal_event_sym == NULL) {
// setup when loading the first TypeArrayKlass (Universe::genesis) hence single threaded invariant
- jdk_internal_event_sym = SymbolTable::new_permanent_symbol("jdk/internal/event/Event", Thread::current());
+ jdk_internal_event_sym = SymbolTable::new_permanent_symbol("jdk/internal/event/Event");
}
assert(jdk_internal_event_sym != NULL, "invariant");
static const Symbol* jdk_jfr_event_sym = NULL;
if (jdk_jfr_event_sym == NULL) {
// setup when loading the first TypeArrayKlass (Universe::genesis) hence single threaded invariant
- jdk_jfr_event_sym = SymbolTable::new_permanent_symbol("jdk/jfr/Event", Thread::current());
+ jdk_jfr_event_sym = SymbolTable::new_permanent_symbol("jdk/jfr/Event");
}
assert(jdk_jfr_event_sym != NULL, "invariant");
const Symbol* const klass_name = klass->name();
--- a/src/hotspot/share/jfr/utilities/jfrJavaLog.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jfr/utilities/jfrJavaLog.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, 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
@@ -62,8 +62,8 @@
JavaValue result(T_VOID);
JfrJavaArguments args(&result);
args.set_klass(JfrJavaSupport::klass(lt));
- args.set_name("tagSetLevel", CHECK);
- args.set_signature("I", CHECK);
+ args.set_name("tagSetLevel");
+ args.set_signature("I");
args.set_receiver(JfrJavaSupport::resolve_non_null(lt));
args.push_int(llt);
JfrJavaSupport::set_field(&args, THREAD);
--- a/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp Wed May 15 13:54:43 2019 +0530
@@ -76,55 +76,55 @@
static bool setup_event_writer_offsets(TRAPS) {
const char class_name[] = "jdk/jfr/internal/EventWriter";
- Symbol* const k_sym = SymbolTable::lookup(class_name, sizeof class_name - 1, CHECK_false);
+ Symbol* const k_sym = SymbolTable::new_symbol(class_name);
assert(k_sym != NULL, "invariant");
Klass* klass = SystemDictionary::resolve_or_fail(k_sym, true, CHECK_false);
assert(klass != NULL, "invariant");
const char start_pos_name[] = "startPosition";
- Symbol* const start_pos_sym = SymbolTable::lookup(start_pos_name, sizeof start_pos_name - 1, CHECK_false);
+ Symbol* const start_pos_sym = SymbolTable::new_symbol(start_pos_name);
assert(start_pos_sym != NULL, "invariant");
assert(invalid_offset == start_pos_offset, "invariant");
compute_offset(start_pos_offset, klass, start_pos_sym, vmSymbols::long_signature());
assert(start_pos_offset != invalid_offset, "invariant");
const char start_pos_address_name[] = "startPositionAddress";
- Symbol* const start_pos_address_sym = SymbolTable::lookup(start_pos_address_name, sizeof start_pos_address_name - 1, CHECK_false);
+ Symbol* const start_pos_address_sym = SymbolTable::new_symbol(start_pos_address_name);
assert(start_pos_address_sym != NULL, "invariant");
assert(invalid_offset == start_pos_address_offset, "invariant");
compute_offset(start_pos_address_offset, klass, start_pos_address_sym, vmSymbols::long_signature());
assert(start_pos_address_offset != invalid_offset, "invariant");
const char event_pos_name[] = "currentPosition";
- Symbol* const event_pos_sym = SymbolTable::lookup(event_pos_name, sizeof event_pos_name - 1, CHECK_false);
+ Symbol* const event_pos_sym = SymbolTable::new_symbol(event_pos_name);
assert(event_pos_sym != NULL, "invariant");
assert(invalid_offset == current_pos_offset, "invariant");
compute_offset(current_pos_offset, klass, event_pos_sym,vmSymbols::long_signature());
assert(current_pos_offset != invalid_offset, "invariant");
const char max_pos_name[] = "maxPosition";
- Symbol* const max_pos_sym = SymbolTable::lookup(max_pos_name, sizeof max_pos_name - 1, CHECK_false);
+ Symbol* const max_pos_sym = SymbolTable::new_symbol(max_pos_name);
assert(max_pos_sym != NULL, "invariant");
assert(invalid_offset == max_pos_offset, "invariant");
compute_offset(max_pos_offset, klass, max_pos_sym, vmSymbols::long_signature());
assert(max_pos_offset != invalid_offset, "invariant");
const char max_event_size_name[] = "maxEventSize";
- Symbol* const max_event_size_sym = SymbolTable::lookup(max_event_size_name, sizeof max_event_size_name - 1, CHECK_false);
+ Symbol* const max_event_size_sym = SymbolTable::new_symbol(max_event_size_name);
assert (max_event_size_sym != NULL, "invariant");
assert(invalid_offset == max_event_size_offset, "invariant");
compute_offset(max_event_size_offset, klass, max_event_size_sym, vmSymbols::int_signature());
assert(max_event_size_offset != invalid_offset, "invariant");
const char notified_name[] = "notified";
- Symbol* const notified_sym = SymbolTable::lookup(notified_name, sizeof notified_name - 1, CHECK_false);
+ Symbol* const notified_sym = SymbolTable::new_symbol(notified_name);
assert (notified_sym != NULL, "invariant");
assert(invalid_offset == notified_offset, "invariant");
compute_offset(notified_offset, klass, notified_sym, vmSymbols::bool_signature());
assert(notified_offset != invalid_offset, "invariant");
const char valid_name[] = "valid";
- Symbol* const valid_sym = SymbolTable::lookup(valid_name, sizeof valid_name - 1, CHECK_false);
+ Symbol* const valid_sym = SymbolTable::new_symbol(valid_name);
assert (valid_sym != NULL, "invariant");
assert(invalid_offset == valid_offset, "invariant");
compute_offset(valid_offset, klass, valid_sym, vmSymbols::bool_signature());
--- a/src/hotspot/share/jvmci/compilerRuntime.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jvmci/compilerRuntime.cpp Wed May 15 13:54:43 2019 +0530
@@ -45,8 +45,7 @@
// First 2 bytes of name contains length (number of bytes).
int len = Bytes::get_Java_u2((address)name);
name += 2;
- TempNewSymbol sym = SymbolTable::new_symbol(name, len, CHECK);
- str = StringTable::intern(sym, CHECK);
+ str = StringTable::intern(name, CHECK);
assert(java_lang_String::is_instance(str), "must be string");
*(oop*)string_result = str; // Store result
}
@@ -78,7 +77,7 @@
name++;
len -= 2;
}
- TempNewSymbol sym = SymbolTable::new_symbol(name, len, CHECK_NULL);
+ TempNewSymbol sym = SymbolTable::new_symbol(name, len);
if (sym == NULL) {
return NULL;
}
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Wed May 15 13:54:43 2019 +0530
@@ -506,7 +506,7 @@
C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, jclass accessing_class, jboolean resolve))
JVMCIObject name = JVMCIENV->wrap(jname);
const char* str = JVMCIENV->as_utf8_string(name);
- TempNewSymbol class_name = SymbolTable::new_symbol(str, CHECK_NULL);
+ TempNewSymbol class_name = SymbolTable::new_symbol(str);
if (class_name->utf8_length() <= 1) {
JVMCI_THROW_MSG_0(InternalError, err_msg("Primitive type %s should be handled in Java code", class_name->as_C_string()));
@@ -537,8 +537,7 @@
// This is a name from a signature. Strip off the trimmings.
// Call recursive to keep scope of strippedsym.
TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1,
- class_name->utf8_length()-2,
- CHECK_0);
+ class_name->utf8_length()-2);
resolved_klass = SystemDictionary::find(strippedsym, class_loader, protection_domain, CHECK_0);
} else if (FieldType::is_array(class_name)) {
FieldArrayInfo fd;
@@ -547,8 +546,7 @@
BasicType t = FieldType::get_array_info(class_name, fd, CHECK_0);
if (t == T_OBJECT) {
TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1+fd.dimension(),
- class_name->utf8_length()-2-fd.dimension(),
- CHECK_0);
+ class_name->utf8_length()-2-fd.dimension());
resolved_klass = SystemDictionary::find(strippedsym,
class_loader,
protection_domain,
@@ -1762,7 +1760,7 @@
C2V_VMENTRY(void, compileToBytecode, (JNIEnv* env, jobject, jobject lambda_form_handle))
Handle lambda_form = JVMCIENV->asConstant(JVMCIENV->wrap(lambda_form_handle), JVMCI_CHECK);
if (lambda_form->is_a(SystemDictionary::LambdaForm_klass())) {
- TempNewSymbol compileToBytecode = SymbolTable::new_symbol("compileToBytecode", CHECK);
+ TempNewSymbol compileToBytecode = SymbolTable::new_symbol("compileToBytecode");
JavaValue result(T_VOID);
JavaCalls::call_special(&result, lambda_form, SystemDictionary::LambdaForm_klass(), compileToBytecode, vmSymbols::void_method_signature(), CHECK);
} else {
--- a/src/hotspot/share/jvmci/jvmciEnv.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jvmci/jvmciEnv.cpp Wed May 15 13:54:43 2019 +0530
@@ -92,7 +92,7 @@
}
// Get the serialized saved properties from HotSpot
- TempNewSymbol serializeSavedProperties = SymbolTable::new_symbol("serializeSavedProperties", CHECK_EXIT);
+ TempNewSymbol serializeSavedProperties = SymbolTable::new_symbol("serializeSavedProperties");
JavaValue result(T_OBJECT);
JavaCallArguments args;
JavaCalls::call_static(&result, ik, serializeSavedProperties, vmSymbols::serializePropertiesToByteArray_signature(), &args, THREAD);
--- a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp Wed May 15 13:54:43 2019 +0530
@@ -139,7 +139,7 @@
#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) \
check_resolve_method(#hsCallType, k, vmSymbols::methodName##_name(), vmSymbols::signatureSymbolName(), CHECK);
#define CONSTRUCTOR(className, signature) { \
- TempNewSymbol sig = SymbolTable::new_symbol(signature, CHECK); \
+ TempNewSymbol sig = SymbolTable::new_symbol(signature); \
check_resolve_method("call_special", k, vmSymbols::object_initializer_name(), sig, CHECK); \
}
#endif
--- a/src/hotspot/share/jvmci/jvmciRuntime.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp Wed May 15 13:54:43 2019 +0530
@@ -469,20 +469,20 @@
JRT_END
JRT_ENTRY(void, JVMCIRuntime::throw_and_post_jvmti_exception(JavaThread* thread, const char* exception, const char* message))
- TempNewSymbol symbol = SymbolTable::new_symbol(exception, CHECK);
+ TempNewSymbol symbol = SymbolTable::new_symbol(exception);
SharedRuntime::throw_and_post_jvmti_exception(thread, symbol, message);
JRT_END
JRT_ENTRY(void, JVMCIRuntime::throw_klass_external_name_exception(JavaThread* thread, const char* exception, Klass* klass))
ResourceMark rm(thread);
- TempNewSymbol symbol = SymbolTable::new_symbol(exception, CHECK);
+ TempNewSymbol symbol = SymbolTable::new_symbol(exception);
SharedRuntime::throw_and_post_jvmti_exception(thread, symbol, klass->external_name());
JRT_END
JRT_ENTRY(void, JVMCIRuntime::throw_class_cast_exception(JavaThread* thread, const char* exception, Klass* caster_klass, Klass* target_klass))
ResourceMark rm(thread);
const char* message = SharedRuntime::generate_class_cast_message(caster_klass, target_klass);
- TempNewSymbol symbol = SymbolTable::new_symbol(exception, CHECK);
+ TempNewSymbol symbol = SymbolTable::new_symbol(exception);
SharedRuntime::throw_and_post_jvmti_exception(thread, symbol, message);
JRT_END
@@ -1011,8 +1011,7 @@
// This is a name from a signature. Strip off the trimmings.
// Call recursive to keep scope of strippedsym.
TempNewSymbol strippedsym = SymbolTable::new_symbol(sym->as_utf8()+1,
- sym->utf8_length()-2,
- CHECK_NULL);
+ sym->utf8_length()-2);
return get_klass_by_name_impl(accessing_klass, cpool, strippedsym, require_local);
}
@@ -1045,8 +1044,7 @@
// We have an unloaded array.
// Build it on the fly if the element class exists.
TempNewSymbol elem_sym = SymbolTable::new_symbol(sym->as_utf8()+1,
- sym->utf8_length()-1,
- CHECK_NULL);
+ sym->utf8_length()-1);
// Get element Klass recursively.
Klass* elem_klass =
--- a/src/hotspot/share/logging/logPrefix.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/logging/logPrefix.hpp Wed May 15 13:54:43 2019 +0530
@@ -71,6 +71,8 @@
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, ref)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, start)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, task)) \
+ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, verify)) \
+ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, verify, start)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, plab)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, promotion)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, region)) \
@@ -88,6 +90,8 @@
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task, time)) \
DEBUG_ONLY(LOG_PREFIX(Test_log_prefix_prefixer, LOG_TAGS(logging, test))) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, tlab)) \
+ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, verify)) \
+ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, verify, start)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, workgang))
--- a/src/hotspot/share/memory/filemap.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/memory/filemap.cpp Wed May 15 13:54:43 2019 +0530
@@ -877,7 +877,7 @@
MemTracker::record_virtual_memory_type((address)base, mtClassShared);
#endif
- if (!verify_region_checksum(i)) {
+ if (VerifySharedSpaces && !verify_region_checksum(i)) {
return NULL;
}
@@ -1143,9 +1143,11 @@
bool FileMapInfo::verify_mapped_heap_regions(int first, int num) {
assert(num > 0, "sanity");
- for (int i = first; i < first + num; i++) {
- if (!verify_region_checksum(i)) {
- return false;
+ if (VerifySharedSpaces) {
+ for (int i = first; i < first + num; i++) {
+ if (!verify_region_checksum(i)) {
+ return false;
+ }
}
}
return true;
@@ -1204,9 +1206,7 @@
#endif // INCLUDE_CDS_JAVA_HEAP
bool FileMapInfo::verify_region_checksum(int i) {
- if (!VerifySharedSpaces) {
- return true;
- }
+ assert(VerifySharedSpaces, "sanity");
size_t sz = space_at(i)->_used;
--- a/src/hotspot/share/memory/heapShared.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/memory/heapShared.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -884,8 +884,8 @@
int num, Thread* THREAD) {
for (int i = 0; i < num; i++) {
ArchivableStaticFieldInfo* info = &fields[i];
- TempNewSymbol klass_name = SymbolTable::new_symbol(info->klass_name, THREAD);
- TempNewSymbol field_name = SymbolTable::new_symbol(info->field_name, THREAD);
+ TempNewSymbol klass_name = SymbolTable::new_symbol(info->klass_name);
+ TempNewSymbol field_name = SymbolTable::new_symbol(info->field_name);
Klass* k = SystemDictionary::resolve_or_null(klass_name, THREAD);
assert(k != NULL && !HAS_PENDING_EXCEPTION, "class must exist");
--- a/src/hotspot/share/memory/metaspace.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/memory/metaspace.cpp Wed May 15 13:54:43 2019 +0530
@@ -47,6 +47,7 @@
#include "utilities/debug.hpp"
#include "utilities/formatBuffer.hpp"
#include "utilities/globalDefinitions.hpp"
+#include "utilities/vmError.hpp"
using namespace metaspace;
@@ -917,31 +918,6 @@
#endif
}
-// Utils to check if a pointer or range is part of a committed metaspace region.
-metaspace::VirtualSpaceNode* MetaspaceUtils::find_enclosing_virtual_space(const void* p) {
- MutexLocker cl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag);
- VirtualSpaceNode* vsn = Metaspace::space_list()->find_enclosing_space(p);
- if (Metaspace::using_class_space() && vsn == NULL) {
- vsn = Metaspace::class_space_list()->find_enclosing_space(p);
- }
- return vsn;
-}
-
-bool MetaspaceUtils::is_range_in_committed(const void* from, const void* to) {
-#if INCLUDE_CDS
- if (UseSharedSpaces) {
- for (int idx = MetaspaceShared::ro; idx <= MetaspaceShared::mc; idx++) {
- if (FileMapInfo::current_info()->is_in_shared_region(from, idx)) {
- return FileMapInfo::current_info()->is_in_shared_region(to, idx);
- }
- }
- }
-#endif
- VirtualSpaceNode* vsn = find_enclosing_virtual_space(from);
- return (vsn != NULL) && vsn->contains(to);
-}
-
-
// Metaspace methods
size_t Metaspace::_first_chunk_word_size = 0;
--- a/src/hotspot/share/memory/metaspace.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/memory/metaspace.hpp Wed May 15 13:54:43 2019 +0530
@@ -329,11 +329,6 @@
// Helper for print_xx_report.
static void print_vs(outputStream* out, size_t scale);
- // Utils to check if a pointer or range is part of a committed metaspace region
- // without acquiring any locks.
- static metaspace::VirtualSpaceNode* find_enclosing_virtual_space(const void* p);
- static bool is_range_in_committed(const void* from, const void* to);
-
public:
// Collect used metaspace statistics. This involves walking the CLDG. The resulting
--- a/src/hotspot/share/memory/metaspaceShared.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/memory/metaspaceShared.cpp Wed May 15 13:54:43 2019 +0530
@@ -371,7 +371,7 @@
utf8_buffer[utf8_length] = '\0';
if (prefix_type == HashtableTextDump::SymbolPrefix) {
- SymbolTable::new_permanent_symbol(utf8_buffer, THREAD);
+ SymbolTable::new_permanent_symbol(utf8_buffer);
} else{
assert(prefix_type == HashtableTextDump::StringPrefix, "Sanity");
oop s = StringTable::intern(utf8_buffer, THREAD);
--- a/src/hotspot/share/memory/universe.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/memory/universe.cpp Wed May 15 13:54:43 2019 +0530
@@ -807,7 +807,7 @@
Symbol* signature,
bool is_static, TRAPS)
{
- TempNewSymbol name = SymbolTable::new_symbol(method, CHECK);
+ TempNewSymbol name = SymbolTable::new_symbol(method);
Method* m = NULL;
// The klass must be linked before looking up the method.
if (!ik->link_class_or_fail(THREAD) ||
--- a/src/hotspot/share/oops/instanceKlass.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/oops/instanceKlass.cpp Wed May 15 13:54:43 2019 +0530
@@ -2611,7 +2611,7 @@
if (package_name == NULL) {
return NULL;
}
- Symbol* pkg_name = SymbolTable::new_symbol(package_name, THREAD);
+ Symbol* pkg_name = SymbolTable::new_symbol(package_name);
return pkg_name;
}
}
--- a/src/hotspot/share/oops/klass.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/oops/klass.cpp Wed May 15 13:54:43 2019 +0530
@@ -813,7 +813,7 @@
if ((size_t)k < os::min_page_size()) return false;
if (!os::is_readable_range(k, k + 1)) return false;
- if (!MetaspaceUtils::is_range_in_committed(k, k + 1)) return false;
+ if (!Metaspace::contains(k)) return false;
if (!Symbol::is_valid(k->name())) return false;
return ClassLoaderDataGraph::is_valid(k->class_loader_data());
--- a/src/hotspot/share/oops/klass.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/oops/klass.hpp Wed May 15 13:54:43 2019 +0530
@@ -333,6 +333,7 @@
static ByteSize secondary_super_cache_offset() { return in_ByteSize(offset_of(Klass, _secondary_super_cache)); }
static ByteSize secondary_supers_offset() { return in_ByteSize(offset_of(Klass, _secondary_supers)); }
static ByteSize java_mirror_offset() { return in_ByteSize(offset_of(Klass, _java_mirror)); }
+ static ByteSize class_loader_data_offset() { return in_ByteSize(offset_of(Klass, _class_loader_data)); }
static ByteSize modifier_flags_offset() { return in_ByteSize(offset_of(Klass, _modifier_flags)); }
static ByteSize layout_helper_offset() { return in_ByteSize(offset_of(Klass, _layout_helper)); }
static ByteSize access_flags_offset() { return in_ByteSize(offset_of(Klass, _access_flags)); }
--- a/src/hotspot/share/oops/method.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/oops/method.cpp Wed May 15 13:54:43 2019 +0530
@@ -1579,7 +1579,7 @@
Symbol* signature = m->signature();
for(SignatureStream ss(signature); !ss.is_done(); ss.next()) {
if (ss.is_object()) {
- Symbol* sym = ss.as_symbol(CHECK_(false));
+ Symbol* sym = ss.as_symbol();
Symbol* name = sym;
Klass* klass = SystemDictionary::resolve_or_null(name, class_loader,
protection_domain, THREAD);
--- a/src/hotspot/share/oops/objArrayKlass.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/oops/objArrayKlass.cpp Wed May 15 13:54:43 2019 +0530
@@ -116,7 +116,7 @@
new_str[idx++] = ';';
}
new_str[idx++] = '\0';
- name = SymbolTable::new_permanent_symbol(new_str, CHECK_0);
+ name = SymbolTable::new_permanent_symbol(new_str);
if (element_klass->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(element_klass);
ik->set_array_name(name);
--- a/src/hotspot/share/oops/oop.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/oops/oop.cpp Wed May 15 13:54:43 2019 +0530
@@ -182,9 +182,7 @@
if (!Universe::heap()->is_in(obj)) return false;
Klass* k = (Klass*)load_klass_raw(obj);
-
- if (!os::is_readable_range(k, k + 1)) return false;
- return MetaspaceUtils::is_range_in_committed(k, k + 1);
+ return Klass::is_valid(k);
}
oop oopDesc::oop_or_null(address addr) {
--- a/src/hotspot/share/oops/symbol.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/oops/symbol.cpp Wed May 15 13:54:43 2019 +0530
@@ -57,13 +57,13 @@
}
}
-void* Symbol::operator new(size_t sz, int len, TRAPS) throw() {
+void* Symbol::operator new(size_t sz, int len) throw() {
int alloc_size = size(len)*wordSize;
address res = (address) AllocateHeap(alloc_size, mtSymbol);
return res;
}
-void* Symbol::operator new(size_t sz, int len, Arena* arena, TRAPS) throw() {
+void* Symbol::operator new(size_t sz, int len, Arena* arena) throw() {
int alloc_size = size(len)*wordSize;
address res = (address)arena->Amalloc_4(alloc_size);
return res;
--- a/src/hotspot/share/oops/symbol.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/oops/symbol.hpp Wed May 15 13:54:43 2019 +0530
@@ -132,8 +132,8 @@
}
Symbol(const u1* name, int length, int refcount);
- void* operator new(size_t size, int len, TRAPS) throw();
- void* operator new(size_t size, int len, Arena* arena, TRAPS) throw();
+ void* operator new(size_t size, int len) throw();
+ void* operator new(size_t size, int len, Arena* arena) throw();
void operator delete(void* p);
--- a/src/hotspot/share/oops/typeArrayKlass.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/oops/typeArrayKlass.cpp Wed May 15 13:54:43 2019 +0530
@@ -47,7 +47,7 @@
const char* name_str, TRAPS) {
Symbol* sym = NULL;
if (name_str != NULL) {
- sym = SymbolTable::new_permanent_symbol(name_str, CHECK_NULL);
+ sym = SymbolTable::new_permanent_symbol(name_str);
}
ClassLoaderData* null_loader_data = ClassLoaderData::the_null_class_loader_data();
--- a/src/hotspot/share/prims/jni.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/prims/jni.cpp Wed May 15 13:54:43 2019 +0530
@@ -329,7 +329,7 @@
name);
return 0;
}
- class_name = SymbolTable::new_symbol(name, CHECK_NULL);
+ class_name = SymbolTable::new_symbol(name);
}
ResourceMark rm(THREAD);
ClassFileStream st((u1*)buf, bufLen, NULL, ClassFileStream::verify);
@@ -416,7 +416,7 @@
}
}
- TempNewSymbol sym = SymbolTable::new_symbol(name, CHECK_NULL);
+ TempNewSymbol sym = SymbolTable::new_symbol(name);
result = find_class_from_class_loader(env, sym, true, loader,
protection_domain, true, thread);
@@ -3288,7 +3288,7 @@
Handle loader; // null (bootstrap) loader
Handle protection_domain; // null protection domain
- TempNewSymbol sym = SymbolTable::new_symbol(name, CHECK_NULL);
+ TempNewSymbol sym = SymbolTable::new_symbol(name);
jclass result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, CHECK_NULL);
if (log_is_enabled(Debug, class, resolve) && result != NULL) {
--- a/src/hotspot/share/prims/jvm.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/prims/jvm.cpp Wed May 15 13:54:43 2019 +0530
@@ -138,9 +138,9 @@
vframeStream vfst(jthread);
// scan up the stack skipping ClassLoader, AccessController and PrivilegedAction frames
- TempNewSymbol access_controller = SymbolTable::new_symbol("java/security/AccessController", CHECK);
+ TempNewSymbol access_controller = SymbolTable::new_symbol("java/security/AccessController");
Klass* access_controller_klass = SystemDictionary::resolve_or_fail(access_controller, false, CHECK);
- TempNewSymbol privileged_action = SymbolTable::new_symbol("java/security/PrivilegedAction", CHECK);
+ TempNewSymbol privileged_action = SymbolTable::new_symbol("java/security/PrivilegedAction");
Klass* privileged_action_klass = SystemDictionary::resolve_or_fail(privileged_action, false, CHECK);
Method* last_caller = NULL;
@@ -786,7 +786,7 @@
return NULL;
}
- TempNewSymbol h_name = SymbolTable::new_symbol(name, CHECK_NULL);
+ TempNewSymbol h_name = SymbolTable::new_symbol(name);
Klass* k = SystemDictionary::resolve_or_null(h_name, CHECK_NULL);
if (k == NULL) {
return NULL;
@@ -810,7 +810,7 @@
THROW_MSG_0(vmSymbols::java_lang_ClassNotFoundException(), name);
}
- TempNewSymbol h_name = SymbolTable::new_symbol(name, CHECK_NULL);
+ TempNewSymbol h_name = SymbolTable::new_symbol(name);
oop loader_oop = JNIHandles::resolve(loader);
oop from_class = JNIHandles::resolve(caller);
@@ -852,7 +852,7 @@
name);
return 0;
}
- TempNewSymbol h_name = SymbolTable::new_symbol(name, CHECK_NULL);
+ TempNewSymbol h_name = SymbolTable::new_symbol(name);
oop from_class_oop = JNIHandles::resolve(from);
Klass* from_class = (from_class_oop == NULL)
? (Klass*)NULL
@@ -933,7 +933,7 @@
name);
return 0;
}
- class_name = SymbolTable::new_symbol(name, str_len, CHECK_NULL);
+ class_name = SymbolTable::new_symbol(name, str_len);
}
ResourceMark rm(THREAD);
@@ -989,7 +989,7 @@
// into the constant pool.
return NULL;
}
- TempNewSymbol klass_name = SymbolTable::new_symbol(str, str_len, CHECK_NULL);
+ TempNewSymbol klass_name = SymbolTable::new_symbol(str, str_len);
// Security Note:
// The Java level wrapper will perform the necessary security check allowing
--- a/src/hotspot/share/prims/jvmti.xml Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/prims/jvmti.xml Wed May 15 13:54:43 2019 +0530
@@ -26,10 +26,7 @@
<!DOCTYPE specification [
<!ELEMENT specification (title, intro*, functionsection, errorsection,
eventsection, datasection, issuessection, changehistory)>
- <!ATTLIST specification label CDATA #REQUIRED
- majorversion CDATA #REQUIRED
- minorversion CDATA #REQUIRED
- microversion CDATA #REQUIRED>
+ <!ATTLIST specification label CDATA #REQUIRED>
<!ELEMENT title (#PCDATA|jvmti|tm)*>
<!ATTLIST title subtitle CDATA #REQUIRED>
@@ -357,10 +354,7 @@
<!ELEMENT li ANY>
]>
-<specification label="JVM(TM) Tool Interface"
- majorversion="11"
- minorversion="0"
- microversion="0">
+<specification label="JVM(TM) Tool Interface">
<title subtitle="Version">
<tm>JVM</tm> Tool Interface
</title>
--- a/src/hotspot/share/prims/jvmti.xsl Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/prims/jvmti.xsl Wed May 15 13:54:43 2019 +0530
@@ -1899,12 +1899,20 @@
</dd>
</xsl:template>
+<xsl:template name="lastchangeversion">
+ <xsl:for-each select="//change">
+ <xsl:if test="position() = last()">
+ <xsl:value-of select="@version"/>
+ </xsl:if>
+ </xsl:for-each>
+</xsl:template>
+
<xsl:template match="changehistory">
<div class="sep"/>
<hr class="thick"/>
<h2>Change History</h2>
Last update: <xsl:value-of select="@update"/><br/>
- Version: <xsl:call-template name="showversion"/>
+ Version: <xsl:call-template name="lastchangeversion"/>
<div class="sep"/>
<xsl:apply-templates select="intro"/>
<div class="sep"/>
--- a/src/hotspot/share/prims/jvmtiExport.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/prims/jvmtiExport.cpp Wed May 15 13:54:43 2019 +0530
@@ -383,7 +383,10 @@
}
break;
default:
- return JNI_EVERSION; // unsupported major version number
+ // Starting from 13 we do not care about minor version anymore
+ if (major < 13 || major > Abstract_VM_Version::vm_major_version()) {
+ return JNI_EVERSION; // unsupported major version number
+ }
}
if (JvmtiEnv::get_phase() == JVMTI_PHASE_LIVE) {
--- a/src/hotspot/share/prims/jvmtiH.xsl Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/prims/jvmtiH.xsl Wed May 15 13:54:43 2019 +0530
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (c) 2002, 2018, 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
@@ -117,10 +117,10 @@
JVMTI_VERSION_11 = 0x300B0000,
JVMTI_VERSION = 0x30000000 + (</xsl:text>
- <xsl:value-of select="//specification/@majorversion"/>
+ <xsl:value-of select="$majorversion"/>
<xsl:text> * 0x10000) + (</xsl:text>
- <xsl:value-of select="//specification/@minorversion"/>
- <xsl:text> * 0x100)</xsl:text>
+ <!-- Now minorversion is always 0 -->
+ <xsl:text> 0 * 0x100)</xsl:text>
<xsl:variable name="micro">
<xsl:call-template name="microversion"/>
</xsl:variable>
--- a/src/hotspot/share/prims/jvmtiImpl.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/prims/jvmtiImpl.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -609,7 +609,7 @@
ty_sign++;
len -= 2;
}
- TempNewSymbol ty_sym = SymbolTable::new_symbol(ty_sign, len, thread);
+ TempNewSymbol ty_sym = SymbolTable::new_symbol(ty_sign, len);
if (klass->name() == ty_sym) {
return true;
}
--- a/src/hotspot/share/prims/jvmtiLib.xsl Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/prims/jvmtiLib.xsl Wed May 15 13:54:43 2019 +0530
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (c) 2002, 2018, 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
@@ -27,14 +27,17 @@
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
+ <xsl:param name="majorversion"></xsl:param>
+
<xsl:template name="microversion">
- <xsl:value-of select="//specification/@microversion"/>
+ <!-- Now microversion is always 0 -->
+ <xsl:text>0</xsl:text>
</xsl:template>
<xsl:template name="showbasicversion">
- <xsl:value-of select="//specification/@majorversion"/>
- <xsl:text>.</xsl:text>
- <xsl:value-of select="//specification/@minorversion"/>
+ <xsl:value-of select="$majorversion"/>
+ <!-- Now minorversion is always 0 -->
+ <xsl:text>.0</xsl:text>
</xsl:template>
<xsl:template name="showversion">
--- a/src/hotspot/share/prims/methodHandles.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/prims/methodHandles.cpp Wed May 15 13:54:43 2019 +0530
@@ -519,12 +519,12 @@
// convert the external string or reflective type to an internal signature
Symbol* MethodHandles::lookup_signature(oop type_str, bool intern_if_not_found, TRAPS) {
if (java_lang_invoke_MethodType::is_instance(type_str)) {
- return java_lang_invoke_MethodType::as_signature(type_str, intern_if_not_found, THREAD);
+ return java_lang_invoke_MethodType::as_signature(type_str, intern_if_not_found);
} else if (java_lang_Class::is_instance(type_str)) {
- return java_lang_Class::as_signature(type_str, false, THREAD);
+ return java_lang_Class::as_signature(type_str, false);
} else if (java_lang_String::is_instance_inlined(type_str)) {
if (intern_if_not_found) {
- return java_lang_String::as_symbol(type_str, THREAD);
+ return java_lang_String::as_symbol(type_str);
} else {
return java_lang_String::as_symbol_or_null(type_str);
}
@@ -602,7 +602,7 @@
}
const char* sigstr = buffer.base();
int siglen = (int) buffer.size();
- bsig = SymbolTable::new_symbol(sigstr, siglen, THREAD);
+ bsig = SymbolTable::new_symbol(sigstr, siglen);
}
assert(is_basic_type_signature(bsig) ||
// detune assert in case the injected argument is not a basic type:
--- a/src/hotspot/share/prims/nativeLookup.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/prims/nativeLookup.cpp Wed May 15 13:54:43 2019 +0530
@@ -407,9 +407,9 @@
address NativeLookup::base_library_lookup(const char* class_name, const char* method_name, const char* signature) {
EXCEPTION_MARK;
bool in_base_library = true; // SharedRuntime inits some math methods.
- TempNewSymbol c_name = SymbolTable::new_symbol(class_name, CATCH);
- TempNewSymbol m_name = SymbolTable::new_symbol(method_name, CATCH);
- TempNewSymbol s_name = SymbolTable::new_symbol(signature, CATCH);
+ TempNewSymbol c_name = SymbolTable::new_symbol(class_name);
+ TempNewSymbol m_name = SymbolTable::new_symbol(method_name);
+ TempNewSymbol s_name = SymbolTable::new_symbol(signature);
// Find the class
Klass* k = SystemDictionary::resolve_or_fail(c_name, true, CATCH);
--- a/src/hotspot/share/prims/wbtestmethods/parserTests.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/prims/wbtestmethods/parserTests.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -51,7 +51,7 @@
static const char* lookup_diagnosticArgumentEnum(const char* field_name, oop object) {
Thread* THREAD = Thread::current();
const char* enum_sig = "Lsun/hotspot/parser/DiagnosticCommand$DiagnosticArgumentType;";
- TempNewSymbol enumSigSymbol = SymbolTable::lookup(enum_sig, (int) strlen(enum_sig), THREAD);
+ TempNewSymbol enumSigSymbol = SymbolTable::new_symbol(enum_sig);
int offset = WhiteBox::offset_for_field(field_name, object, enumSigSymbol);
oop enumOop = object->obj_field(offset);
--- a/src/hotspot/share/prims/whitebox.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/prims/whitebox.cpp Wed May 15 13:54:43 2019 +0530
@@ -179,7 +179,7 @@
WB_ENTRY(jboolean, WB_IsClassAlive(JNIEnv* env, jobject target, jstring name))
oop h_name = JNIHandles::resolve(name);
if (h_name == NULL) return false;
- Symbol* sym = java_lang_String::as_symbol(h_name, CHECK_false);
+ Symbol* sym = java_lang_String::as_symbol(h_name);
TempNewSymbol tsym(sym); // Make sure to decrement reference count on sym on return
WBIsKlassAliveClosure closure(sym);
@@ -191,7 +191,7 @@
WB_ENTRY(jint, WB_GetSymbolRefcount(JNIEnv* env, jobject unused, jstring name))
oop h_name = JNIHandles::resolve(name);
if (h_name == NULL) return false;
- Symbol* sym = java_lang_String::as_symbol(h_name, CHECK_0);
+ Symbol* sym = java_lang_String::as_symbol(h_name);
TempNewSymbol tsym(sym); // Make sure to decrement reference count on sym on return
return (jint)sym->refcount();
WB_END
@@ -1996,8 +1996,7 @@
InstanceKlass* ik = InstanceKlass::cast(arg_klass);
//Create symbols to look for in the class
- TempNewSymbol name_symbol = SymbolTable::lookup(field_name, (int) strlen(field_name),
- THREAD);
+ TempNewSymbol name_symbol = SymbolTable::new_symbol(field_name);
//To be filled in with an offset of the field we're looking for
fieldDescriptor fd;
--- a/src/hotspot/share/runtime/arguments.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/runtime/arguments.cpp Wed May 15 13:54:43 2019 +0530
@@ -3792,11 +3792,6 @@
return JNI_ENOMEM;
}
- // Set up VerifySharedSpaces
- if (FLAG_IS_DEFAULT(VerifySharedSpaces) && SharedArchiveFile != NULL) {
- VerifySharedSpaces = true;
- }
-
// Delay warning until here so that we've had a chance to process
// the -XX:-PrintWarnings flag
if (needs_hotspotrc_warning) {
--- a/src/hotspot/share/runtime/deoptimization.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/runtime/deoptimization.cpp Wed May 15 13:54:43 2019 +0530
@@ -1430,7 +1430,7 @@
ResourceMark rm(THREAD);
for (SignatureStream ss(symbol); !ss.is_done(); ss.next()) {
if (ss.is_object()) {
- Symbol* class_name = ss.as_symbol(CHECK);
+ Symbol* class_name = ss.as_symbol();
Handle protection_domain (THREAD, constant_pool->pool_holder()->protection_domain());
SystemDictionary::resolve_or_null(class_name, class_loader, protection_domain, CHECK);
}
--- a/src/hotspot/share/runtime/fieldType.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/runtime/fieldType.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -82,7 +82,7 @@
int len = (int)strlen(element);
assert(element[len-1] == ';', "last char should be a semicolon");
element[len-1] = '\0'; // chop off semicolon
- fd._object_key = SymbolTable::new_symbol(element + 1, CHECK_(T_BYTE));
+ fd._object_key = SymbolTable::new_symbol(element + 1);
}
// Pass dimension back to caller
fd._dimension = dim;
--- a/src/hotspot/share/runtime/globals.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/runtime/globals.hpp Wed May 15 13:54:43 2019 +0530
@@ -2349,8 +2349,7 @@
"Use shared spaces for metadata") \
\
product(bool, VerifySharedSpaces, false, \
- "Verify shared spaces (false for default archive, true for " \
- "archive specified by -XX:SharedArchiveFile)") \
+ "Verify integrity of shared spaces") \
\
product(bool, RequireSharedSpaces, false, \
"Require shared spaces for metadata") \
--- a/src/hotspot/share/runtime/os.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/runtime/os.hpp Wed May 15 13:54:43 2019 +0530
@@ -591,6 +591,7 @@
// Loads .dll/.so and
// in case of error it checks if .dll/.so was built for the
// same architecture as HotSpot is running on
+ // in case of an error NULL is returned and an error message is stored in ebuf
static void* dll_load(const char *name, char *ebuf, int ebuflen);
// lookup symbol in a shared library
--- a/src/hotspot/share/runtime/reflection.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/runtime/reflection.cpp Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -757,7 +757,7 @@
if (T_OBJECT == ss->type() || T_ARRAY == ss->type()) {
- Symbol* name = ss->as_symbol(CHECK_NULL);
+ Symbol* name = ss->as_symbol();
oop loader = method->method_holder()->class_loader();
oop protection_domain = method->method_holder()->protection_domain();
const Klass* k = SystemDictionary::resolve_or_fail(name,
--- a/src/hotspot/share/runtime/signature.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/runtime/signature.cpp Wed May 15 13:54:43 2019 +0530
@@ -336,7 +336,7 @@
return _type == T_ARRAY;
}
-Symbol* SignatureStream::as_symbol(TRAPS) {
+Symbol* SignatureStream::as_symbol() {
// Create a symbol from for string _begin _end
int begin = _begin;
int end = _end;
@@ -368,7 +368,7 @@
// Save names for cleaning up reference count at the end of
// SignatureStream scope.
- name = SymbolTable::new_symbol(symbol_chars, len, CHECK_NULL);
+ name = SymbolTable::new_symbol(symbol_chars, len);
if (!name->is_permanent()) {
if (_names == NULL) {
_names = new GrowableArray<Symbol*>(10);
@@ -380,9 +380,9 @@
}
Klass* SignatureStream::as_klass(Handle class_loader, Handle protection_domain,
- FailureMode failure_mode, TRAPS) {
+ FailureMode failure_mode, TRAPS) {
if (!is_object()) return NULL;
- Symbol* name = as_symbol(CHECK_NULL);
+ Symbol* name = as_symbol();
if (failure_mode == ReturnNull) {
return SystemDictionary::resolve_or_null(name, class_loader, protection_domain, THREAD);
} else {
--- a/src/hotspot/share/runtime/signature.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/runtime/signature.hpp Wed May 15 13:54:43 2019 +0530
@@ -400,7 +400,7 @@
bool is_object() const; // True if this argument is an object
bool is_array() const; // True if this argument is an array
BasicType type() const { return _type; }
- Symbol* as_symbol(TRAPS);
+ Symbol* as_symbol();
enum FailureMode { ReturnNull, NCDFError };
Klass* as_klass(Handle class_loader, Handle protection_domain, FailureMode failure_mode, TRAPS);
oop as_java_mirror(Handle class_loader, Handle protection_domain, FailureMode failure_mode, TRAPS);
--- a/src/hotspot/share/services/attachListener.hpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/services/attachListener.hpp Wed May 15 13:54:43 2019 +0530
@@ -121,7 +121,7 @@
const char* name() const { return _name; }
// set the operation name
- void set_name(char* name) {
+ void set_name(const char* name) {
assert(strlen(name) <= name_length_max, "exceeds maximum name length");
size_t len = MIN2(strlen(name), (size_t)name_length_max);
memcpy(_name, name, len);
@@ -148,7 +148,7 @@
}
// create an operation of a given name
- AttachOperation(char* name) {
+ AttachOperation(const char* name) {
set_name(name);
for (int i=0; i<arg_count_max; i++) {
set_arg(i, NULL);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/utilities/virtualizationSupport.cpp Wed May 15 13:54:43 2019 +0530
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019 SAP SE. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/os.hpp"
+#include "utilities/virtualizationSupport.hpp"
+
+static void *dlHandle = NULL;
+
+static GuestLib_StatGet_t GuestLib_StatGet = NULL;
+static GuestLib_StatFree_t GuestLib_StatFree = NULL;
+
+static bool has_host_information = false;
+static bool has_resource_information = false;
+
+// host + resource information; avoid the session and other special info vectors
+static char host_information[300];
+static char extended_resource_info_at_startup[600];
+
+void VirtualizationSupport::initialize() {
+ // open vmguestlib and bind SDK functions
+ char ebuf[1024];
+ dlHandle = os::dll_load("vmGuestLib", ebuf, sizeof ebuf);
+
+#ifdef LINUX
+ if (dlHandle == NULL) {
+ // the open-vm-tools have a different guest lib name
+ // on some distros e.g. SLES12 the open-vm-tools are the default,
+ // so use the different libname as a fallback
+ dlHandle = os::dll_load("/usr/lib64/libguestlib.so.0", ebuf, sizeof ebuf);
+ }
+#endif
+ if (dlHandle == NULL) {
+ return;
+ }
+
+ GuestLib_StatGet = CAST_TO_FN_PTR(GuestLib_StatGet_t, os::dll_lookup(dlHandle, "VMGuestLib_StatGet"));
+ GuestLib_StatFree = CAST_TO_FN_PTR(GuestLib_StatFree_t, os::dll_lookup(dlHandle, "VMGuestLib_StatFree"));
+
+ if (GuestLib_StatGet != NULL && GuestLib_StatFree != NULL) {
+ char* result_info = NULL;
+ size_t result_size = 0;
+ VMGuestLibError sg_error = GuestLib_StatGet("text", "resources", &result_info, &result_size);
+ if (sg_error == VMGUESTLIB_ERROR_SUCCESS) {
+ has_resource_information = true;
+ snprintf(extended_resource_info_at_startup, sizeof(extended_resource_info_at_startup), "%s", result_info);
+ GuestLib_StatFree(result_info, result_size);
+ }
+ sg_error = GuestLib_StatGet("text", "host", &result_info, &result_size);
+ if (sg_error == VMGUESTLIB_ERROR_SUCCESS) {
+ has_host_information = true;
+ snprintf(host_information, sizeof(host_information), "%s", result_info);
+ GuestLib_StatFree(result_info, result_size);
+ }
+ }
+}
+
+void VirtualizationSupport::print_virtualization_info(outputStream* st) {
+ if (has_host_information) {
+ st->print_cr("vSphere host information:");
+ st->print_cr("%s", host_information);
+ }
+ // resource info at startup
+ if (has_resource_information) {
+ st->print_cr("vSphere resource information collected at VM startup:");
+ st->print_cr("%s", extended_resource_info_at_startup);
+ }
+ // current resource info
+ if (GuestLib_StatGet != NULL && GuestLib_StatFree != NULL) {
+ char* result_info = NULL;
+ size_t result_size = 0;
+ VMGuestLibError sg_error = GuestLib_StatGet("text", "resources", &result_info, &result_size);
+ if (sg_error == VMGUESTLIB_ERROR_SUCCESS) {
+ st->print_cr("vSphere resource information available now:");
+ st->print_cr("%s", result_info);
+ GuestLib_StatFree(result_info, result_size);
+ }
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/utilities/virtualizationSupport.hpp Wed May 15 13:54:43 2019 +0530
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019 SAP SE. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_UTILITIES_VIRTUALIZATIONSUPPORT_HPP
+#define SHARE_UTILITIES_VIRTUALIZATIONSUPPORT_HPP
+
+#include "utilities/ostream.hpp"
+
+typedef enum {
+ VMGUESTLIB_ERROR_SUCCESS = 0, // no error occured
+ VMGUESTLIB_ERROR_OTHER,
+ VMGUESTLIB_ERROR_NOT_RUNNING_IN_VM,
+ VMGUESTLIB_ERROR_NOT_ENABLED,
+ VMGUESTLIB_ERROR_NOT_AVAILABLE,
+ VMGUESTLIB_ERROR_NO_INFO,
+ VMGUESTLIB_ERROR_MEMORY,
+ VMGUESTLIB_ERROR_BUFFER_TOO_SMALL,
+ VMGUESTLIB_ERROR_INVALID_HANDLE,
+ VMGUESTLIB_ERROR_INVALID_ARG,
+ VMGUESTLIB_ERROR_UNSUPPORTED_VERSION
+} VMGuestLibError;
+
+// new SDK functions from VMWare SDK 6.0; need VMware Tools version 9.10 installed
+typedef VMGuestLibError (*GuestLib_StatGet_t)(const char*, const char*, char**, size_t*);
+typedef VMGuestLibError (*GuestLib_StatFree_t)(char*, size_t);
+
+class VirtualizationSupport {
+ public:
+ static void initialize();
+ static void print_virtualization_info(outputStream* st);
+};
+
+#endif
+
--- a/src/hotspot/share/utilities/vmError.cpp Tue May 14 11:23:08 2019 +0530
+++ b/src/hotspot/share/utilities/vmError.cpp Wed May 15 13:54:43 2019 +0530
@@ -1198,8 +1198,7 @@
static int expand_and_open(const char* pattern, char* buf, size_t buflen, size_t pos) {
int fd = -1;
if (Arguments::copy_expand_pid(pattern, strlen(pattern), &buf[pos], buflen - pos)) {
- // the O_EXCL flag will cause the open to fail if the file exists
- fd = open(buf, O_RDWR | O_CREAT | O_EXCL, 0666);
+ fd = open(buf, O_RDWR | O_CREAT, 0666);
}
return fd;
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Tue May 14 11:23:08 2019 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Wed May 15 13:54:43 2019 +0530
@@ -1963,6 +1963,13 @@
return (flags() & LAMBDA_METHOD) == LAMBDA_METHOD;
}
+ /** override this method to point to the original enclosing method if this method symbol represents a synthetic
+ * lambda method
+ */
+ public MethodSymbol originalEnclosingMethod() {
+ return this;
+ }
+
/** The implementation of this (abstract) symbol in class origin;
* null if none exists. Synthetic methods are not considered
* as possible implementations.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Tue May 14 11:23:08 2019 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Wed May 15 13:54:43 2019 +0530
@@ -603,21 +603,6 @@
tree.init = translate(tree.init);
tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
result = tree;
- } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
- JCExpression init = translate(tree.init);
- VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
- int prevPos = make.pos;
- try {
- result = make.at(tree).VarDef(xsym, init);
- } finally {
- make.at(prevPos);
- }
- // Replace the entered symbol for this variable
- WriteableScope sc = tree.sym.owner.members();
- if (sc != null) {
- sc.remove(tree.sym);
- sc.enter(xsym);
- }
} else {
super.visitVarDef(tree);
}
@@ -1572,9 +1557,6 @@
// Check for type variables (including as type arguments).
// If they occur within class nested in a lambda, mark for erasure
Type type = tree.sym.asType();
- if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
- ltc.addSymbol(tree.sym, TYPE_VAR);
- }
}
List<Frame> prevStack = frameStack;
@@ -1944,8 +1926,17 @@
}
// This symbol will be filled-in in complete
- this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
-
+ if (owner.kind == MTH) {
+ final MethodSymbol originalOwner = (MethodSymbol)owner.clone(owner.owner);
+ this.translatedSym = new MethodSymbol(SYNTHETIC | PRIVATE, null, null, owner.enclClass()) {
+ @Override
+ public MethodSymbol originalEnclosingMethod() {
+ return originalOwner;
+ }
+ };
+ } else {
+ this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
+ }
translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
@@ -1953,7 +1944,6 @@
translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
translatedSymbols.put(CAPTURED_OUTER_THIS, new LinkedHashMap<Symbol, Symbol>());
- translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
freeVarProcessedLocalClasses = new HashSet<>();
}
@@ -2046,16 +2036,6 @@
case CAPTURED_THIS:
ret = sym; // self represented
break;
- case TYPE_VAR:
- // Just erase the type var
- ret = new VarSymbol(sym.flags(), sym.name,
- types.erasure(sym.type), sym.owner);
-
- /* this information should also be kept for LVT generation at Gen
- * a Symbol with pos < startPos won't be tracked.
- */
- ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
- break;
case CAPTURED_VAR:
ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, sym.name, types.erasure(sym.type), translatedSym) {
@Override
@@ -2352,8 +2332,7 @@
LOCAL_VAR, // original to translated lambda locals
CAPTURED_VAR, // variables in enclosing scope to translated synthetic parameters
CAPTURED_THIS, // class symbols to translated synthetic parameters (for captured member access)
- CAPTURED_OUTER_THIS, // used when `this' capture is illegal, but outer this capture is legit (JDK-8129740)
- TYPE_VAR; // original to translated lambda type variables
+ CAPTURED_OUTER_THIS; // used when `this' capture is illegal, but outer this capture is legit (JDK-8129740)
boolean propagateAnnotations() {
switch (this) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Tue May 14 11:23:08 2019 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -323,9 +323,9 @@
(c.owner.type == null // local to init block
|| c.owner.kind != MTH) // or member init
? null
- : (MethodSymbol)c.owner;
+ : ((MethodSymbol)c.owner).originalEnclosingMethod();
databuf.appendChar(poolWriter.putClass(enclClass));
- databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(c.owner));
+ databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(enclMethod));
endAttr(alenIdx);
return 1;
}
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPageAllocator.java Tue May 14 11:23:08 2019 +0530
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPageAllocator.java Wed May 15 13:54:43 2019 +0530
@@ -27,8 +27,6 @@
import sun.jvm.hotspot.debugger.Address;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.runtime.VMObject;
-import sun.jvm.hotspot.runtime.VMObjectFactory;
-import sun.jvm.hotspot.types.AddressField;
import sun.jvm.hotspot.types.CIntegerField;
import sun.jvm.hotspot.types.Type;
import sun.jvm.hotspot.types.TypeDataBase;
@@ -37,7 +35,8 @@
public class ZPageAllocator extends VMObject {
- private static long physicalFieldOffset;
+ private static CIntegerField maxCapacityField;
+ private static CIntegerField capacityField;
private static CIntegerField usedField;
static {
@@ -47,21 +46,17 @@
static private synchronized void initialize(TypeDataBase db) {
Type type = db.lookupType("ZPageAllocator");
- physicalFieldOffset = type.getAddressField("_physical").getOffset();
+ maxCapacityField = type.getCIntegerField("_max_capacity");
+ capacityField = type.getCIntegerField("_capacity");
usedField = type.getCIntegerField("_used");
}
- private ZPhysicalMemoryManager physical() {
- Address physicalAddr = addr.addOffsetTo(physicalFieldOffset);
- return (ZPhysicalMemoryManager)VMObjectFactory.newObject(ZPhysicalMemoryManager.class, physicalAddr);
- }
-
public long maxCapacity() {
- return physical().maxCapacity();
+ return maxCapacityField.getValue(addr);
}
public long capacity() {
- return physical().capacity();
+ return capacityField.getValue(addr);
}
public long used() {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPhysicalMemoryManager.java Tue May 14 11:23:08 2019 +0530
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-package sun.jvm.hotspot.gc.z;
-
-import sun.jvm.hotspot.debugger.Address;
-import sun.jvm.hotspot.runtime.VM;
-import sun.jvm.hotspot.runtime.VMObject;
-import sun.jvm.hotspot.types.CIntegerField;
-import sun.jvm.hotspot.types.Type;
-import sun.jvm.hotspot.types.TypeDataBase;
-
-// Mirror class for ZPhysicalMemoryManager
-
-public class ZPhysicalMemoryManager extends VMObject {
-
- private static CIntegerField capacityField;
-
- private static CIntegerField maxCapacityField;
-
- static {
- VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
- }
-
- private static synchronized void initialize(TypeDataBase db) {
- Type type = db.lookupType("ZPhysicalMemoryManager");
-
- capacityField = type.getCIntegerField("_capacity");
- maxCapacityField = type.getCIntegerField("_max_capacity");
- }
-
- public long capacity() {
- return capacityField.getValue(addr);
- }
-
- public long maxCapacity() {
- return maxCapacityField.getValue(addr);
- }
-
- public ZPhysicalMemoryManager(Address addr) {
- super(addr);
- }
-}
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineManagerImpl.java Tue May 14 11:23:08 2019 +0530
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineManagerImpl.java Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -52,7 +52,7 @@
private final ThreadGroup mainGroupForJDI;
private ResourceBundle messages = null;
private int vmSequenceNumber = 0;
- private static final int majorVersion = 11;
+ private static final int majorVersion = Runtime.version().feature();
private static final int minorVersion = 0;
private static final Object lock = new Object();
--- a/src/jdk.jdwp.agent/share/native/libjdwp/VirtualMachineImpl.c Tue May 14 11:23:08 2019 +0530
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/VirtualMachineImpl.c Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -35,8 +35,6 @@
#include "FrameID.h"
static char *versionName = "Java Debug Wire Protocol (Reference Implementation)";
-static int majorVersion = 11; /* JDWP major version */
-static int minorVersion = 0; /* JDWP minor version */
static jboolean
version(PacketInputStream *in, PacketOutputStream *out)
@@ -46,6 +44,10 @@
char *vmVersion;
char *vmInfo;
+ /* Now the JDWP versions are the same as JVMTI versions */
+ int majorVersion = jvmtiMajorVersion();
+ int minorVersion = 0;
+
if (gdata->vmDead) {
outStream_setError(out, JDWP_ERROR(VM_DEAD));
return JNI_TRUE;
--- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java Tue May 14 11:23:08 2019 +0530
+++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java Wed May 15 13:54:43 2019 +0530
@@ -1211,7 +1211,7 @@
return 0;
long written = 0;
- if (e.crc != 0 && e.csize > 0) {
+ if (e.csize > 0 && (e.crc != 0 || e.size == 0)) {
// pre-compressed entry, write directly to output stream
writeTo(e, os);
} else {
--- a/test/hotspot/gtest/classfile/test_symbolTable.cpp Tue May 14 11:23:08 2019 +0530
+++ b/test/hotspot/gtest/classfile/test_symbolTable.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, 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
@@ -34,14 +34,14 @@
// the thread should be in vm to use locks
ThreadInVMfromNative ThreadInVMfromNative(THREAD);
- Symbol* abc = SymbolTable::new_symbol("abc", CATCH);
+ Symbol* abc = SymbolTable::new_symbol("abc");
int abccount = abc->refcount();
TempNewSymbol ss = abc;
ASSERT_EQ(ss->refcount(), abccount) << "only one abc";
ASSERT_EQ(ss->refcount(), abc->refcount()) << "should match TempNewSymbol";
- Symbol* efg = SymbolTable::new_symbol("efg", CATCH);
- Symbol* hij = SymbolTable::new_symbol("hij", CATCH);
+ Symbol* efg = SymbolTable::new_symbol("efg");
+ Symbol* hij = SymbolTable::new_symbol("hij");
int efgcount = efg->refcount();
int hijcount = hij->refcount();
@@ -63,12 +63,12 @@
ASSERT_EQ(s1->refcount(), abccount + 1) << "should still be two abc (s1 and ss)";
TempNewSymbol s3;
- Symbol* klm = SymbolTable::new_symbol("klm", CATCH);
+ Symbol* klm = SymbolTable::new_symbol("klm");
int klmcount = klm->refcount();
s3 = klm; // assignment
ASSERT_EQ(s3->refcount(), klmcount) << "only one klm now";
- Symbol* xyz = SymbolTable::new_symbol("xyz", CATCH);
+ Symbol* xyz = SymbolTable::new_symbol("xyz");
int xyzcount = xyz->refcount();
{ // inner scope
TempNewSymbol s_inner = xyz;
@@ -77,7 +77,7 @@
<< "Should have been decremented by dtor in inner scope";
// Test overflowing refcount making symbol permanent
- Symbol* bigsym = SymbolTable::new_symbol("bigsym", CATCH);
+ Symbol* bigsym = SymbolTable::new_symbol("bigsym");
for (int i = 0; i < PERM_REFCOUNT + 100; i++) {
bigsym->increment_refcount();
}
@@ -101,9 +101,8 @@
SymbolThread(Semaphore* post) : JavaTestThread(post) {}
virtual ~SymbolThread() {}
void main_run() {
- Thread* THREAD = Thread::current();
for (int i = 0; i < 1000; i++) {
- TempNewSymbol sym = SymbolTable::new_symbol(symbol_name, CATCH);
+ TempNewSymbol sym = SymbolTable::new_symbol(symbol_name);
// Create and destroy new symbol
EXPECT_TRUE(sym->refcount() != 0) << "Symbol refcount unexpectedly zeroed";
}
@@ -121,12 +120,10 @@
void main_run() {
Semaphore done(0);
- Thread* THREAD = Thread::current();
-
// Find a symbol where there will probably be only one instance.
for (int i = 0; i < 100; i++) {
os::snprintf(symbol_name, SYM_NAME_LENGTH, "some_symbol%d", i);
- TempNewSymbol ts = SymbolTable::new_symbol(symbol_name, CATCH);
+ TempNewSymbol ts = SymbolTable::new_symbol(symbol_name);
if (ts->refcount() == 1) {
EXPECT_TRUE(ts->refcount() == 1) << "Symbol is just created";
break; // found a unique symbol
--- a/test/hotspot/gtest/gc/z/test_zForwarding.cpp Tue May 14 11:23:08 2019 +0530
+++ b/test/hotspot/gtest/gc/z/test_zForwarding.cpp Wed May 15 13:54:43 2019 +0530
@@ -169,9 +169,6 @@
// Teardown forwarding
ZForwarding::destroy(forwarding);
-
- // Teardown page
- page.physical_memory().clear();
}
// Run the given function with a few different input values.
--- a/test/hotspot/gtest/gc/z/test_zPhysicalMemory.cpp Tue May 14 11:23:08 2019 +0530
+++ b/test/hotspot/gtest/gc/z/test_zPhysicalMemory.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, 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
@@ -22,59 +22,121 @@
*/
#include "precompiled.hpp"
-#include "gc/z/zGlobals.hpp"
#include "gc/z/zPhysicalMemory.inline.hpp"
-#include "utilities/debug.hpp"
#include "unittest.hpp"
-#if defined(AMD64)
+TEST(ZPhysicalMemoryTest, copy) {
+ const ZPhysicalMemorySegment seg0(0, 100);
+ const ZPhysicalMemorySegment seg1(200, 100);
+
+ ZPhysicalMemory pmem0;
+ pmem0.add_segment(seg0);
+ EXPECT_EQ(pmem0.nsegments(), 1u);
+ EXPECT_EQ(pmem0.segment(0).size(), 100u);
+
+ ZPhysicalMemory pmem1;
+ pmem1.add_segment(seg0);
+ pmem1.add_segment(seg1);
+ EXPECT_EQ(pmem1.nsegments(), 2u);
+ EXPECT_EQ(pmem1.segment(0).size(), 100u);
+ EXPECT_EQ(pmem1.segment(1).size(), 100u);
-TEST(ZPhysicalMemorySegmentTest, split) {
- ZPhysicalMemorySegment seg(0, 10 * ZGranuleSize);
+ ZPhysicalMemory pmem2(pmem0);
+ EXPECT_EQ(pmem2.nsegments(), 1u);
+ EXPECT_EQ(pmem2.segment(0).size(), 100u);
+
+ pmem2 = pmem1;
+ EXPECT_EQ(pmem2.nsegments(), 2u);
+ EXPECT_EQ(pmem2.segment(0).size(), 100u);
+ EXPECT_EQ(pmem2.segment(1).size(), 100u);
+}
- ZPhysicalMemorySegment seg_split0 = seg.split(0 * ZGranuleSize);
- EXPECT_EQ(seg_split0.size(), 0 * ZGranuleSize);
- EXPECT_EQ( seg.size(), 10 * ZGranuleSize);
+TEST(ZPhysicalMemoryTest, segments) {
+ const ZPhysicalMemorySegment seg0(0, 1);
+ const ZPhysicalMemorySegment seg1(1, 1);
+ const ZPhysicalMemorySegment seg2(2, 1);
+ const ZPhysicalMemorySegment seg3(3, 1);
+ const ZPhysicalMemorySegment seg4(4, 1);
+ const ZPhysicalMemorySegment seg5(5, 1);
+ const ZPhysicalMemorySegment seg6(6, 1);
+
+ ZPhysicalMemory pmem0;
+ EXPECT_EQ(pmem0.nsegments(), 0u);
+ EXPECT_EQ(pmem0.is_null(), true);
- ZPhysicalMemorySegment seg_split1 = seg.split(5 * ZGranuleSize);
- EXPECT_EQ(seg_split1.size(), 5 * ZGranuleSize);
- EXPECT_EQ( seg.size(), 5 * ZGranuleSize);
+ ZPhysicalMemory pmem1;
+ pmem1.add_segment(seg0);
+ pmem1.add_segment(seg1);
+ pmem1.add_segment(seg2);
+ pmem1.add_segment(seg3);
+ pmem1.add_segment(seg4);
+ pmem1.add_segment(seg5);
+ pmem1.add_segment(seg6);
+ EXPECT_EQ(pmem1.nsegments(), 1u);
+ EXPECT_EQ(pmem1.segment(0).size(), 7u);
+ EXPECT_EQ(pmem1.is_null(), false);
+
+ ZPhysicalMemory pmem2;
+ pmem2.add_segment(seg0);
+ pmem2.add_segment(seg1);
+ pmem2.add_segment(seg2);
+ pmem2.add_segment(seg4);
+ pmem2.add_segment(seg5);
+ pmem2.add_segment(seg6);
+ EXPECT_EQ(pmem2.nsegments(), 2u);
+ EXPECT_EQ(pmem2.segment(0).size(), 3u);
+ EXPECT_EQ(pmem2.segment(1).size(), 3u);
+ EXPECT_EQ(pmem2.is_null(), false);
- ZPhysicalMemorySegment seg_split2 = seg.split(5 * ZGranuleSize);
- EXPECT_EQ(seg_split2.size(), 5 * ZGranuleSize);
- EXPECT_EQ( seg.size(), 0 * ZGranuleSize);
+ ZPhysicalMemory pmem3;
+ pmem3.add_segment(seg0);
+ pmem3.add_segment(seg2);
+ pmem3.add_segment(seg3);
+ pmem3.add_segment(seg4);
+ pmem3.add_segment(seg6);
+ EXPECT_EQ(pmem3.nsegments(), 3u);
+ EXPECT_EQ(pmem3.segment(0).size(), 1u);
+ EXPECT_EQ(pmem3.segment(1).size(), 3u);
+ EXPECT_EQ(pmem3.segment(2).size(), 1u);
+ EXPECT_EQ(pmem3.is_null(), false);
- ZPhysicalMemorySegment seg_split3 = seg.split(0 * ZGranuleSize);
- EXPECT_EQ(seg_split3.size(), 0 * ZGranuleSize);
- EXPECT_EQ( seg.size(), 0 * ZGranuleSize);
+ ZPhysicalMemory pmem4;
+ pmem4.add_segment(seg0);
+ pmem4.add_segment(seg2);
+ pmem4.add_segment(seg4);
+ pmem4.add_segment(seg6);
+ EXPECT_EQ(pmem4.nsegments(), 4u);
+ EXPECT_EQ(pmem4.segment(0).size(), 1u);
+ EXPECT_EQ(pmem4.segment(1).size(), 1u);
+ EXPECT_EQ(pmem4.segment(2).size(), 1u);
+ EXPECT_EQ(pmem4.segment(3).size(), 1u);
+ EXPECT_EQ(pmem4.is_null(), false);
}
TEST(ZPhysicalMemoryTest, split) {
- ZPhysicalMemoryManager pmem_manager(10 * ZGranuleSize);
-
- pmem_manager.try_ensure_unused_capacity(10 * ZGranuleSize);
- EXPECT_EQ(pmem_manager.unused_capacity(), 10 * ZGranuleSize);
+ ZPhysicalMemory pmem;
- ZPhysicalMemory pmem = pmem_manager.alloc(8 * ZGranuleSize);
- EXPECT_EQ(pmem.nsegments(), 1u) << "wrong number of segments";
-
- ZPhysicalMemory split0_pmem = pmem.split(ZGranuleSize);
- EXPECT_EQ(split0_pmem.nsegments(), 1u);
- EXPECT_EQ( pmem.nsegments(), 1u);
- EXPECT_EQ(split0_pmem.size(), 1 * ZGranuleSize);
- EXPECT_EQ( pmem.size(), 7 * ZGranuleSize);
+ pmem.add_segment(ZPhysicalMemorySegment(0, 10));
+ pmem.add_segment(ZPhysicalMemorySegment(10, 10));
+ pmem.add_segment(ZPhysicalMemorySegment(30, 10));
+ EXPECT_EQ(pmem.nsegments(), 2u);
+ EXPECT_EQ(pmem.size(), 30u);
- ZPhysicalMemory split1_pmem = pmem.split(2 * ZGranuleSize);
- EXPECT_EQ(split1_pmem.nsegments(), 1u);
- EXPECT_EQ( pmem.nsegments(), 1u);
- EXPECT_EQ(split1_pmem.size(), 2 * ZGranuleSize);
- EXPECT_EQ( pmem.size(), 5 * ZGranuleSize);
+ ZPhysicalMemory pmem0 = pmem.split(1);
+ EXPECT_EQ(pmem0.nsegments(), 1u);
+ EXPECT_EQ(pmem0.size(), 1u);
+ EXPECT_EQ(pmem.nsegments(), 2u);
+ EXPECT_EQ(pmem.size(), 29u);
- ZPhysicalMemory split2_pmem = pmem.split(5 * ZGranuleSize);
- EXPECT_EQ(split2_pmem.nsegments(), 1u);
- EXPECT_EQ( pmem.nsegments(), 1u);
- EXPECT_EQ(split2_pmem.size(), 5 * ZGranuleSize);
- EXPECT_EQ( pmem.size(), 0 * ZGranuleSize);
+ ZPhysicalMemory pmem1 = pmem.split(25);
+ EXPECT_EQ(pmem1.nsegments(), 2u);
+ EXPECT_EQ(pmem1.size(), 25u);
+ EXPECT_EQ(pmem.nsegments(), 1u);
+ EXPECT_EQ(pmem.size(), 4u);
+
+ ZPhysicalMemory pmem2 = pmem.split(4);
+ EXPECT_EQ(pmem2.nsegments(), 1u);
+ EXPECT_EQ(pmem2.size(), 4u);
+ EXPECT_EQ(pmem.nsegments(), 0u);
+ EXPECT_EQ(pmem.size(), 0u);
}
-
-#endif
--- a/test/hotspot/gtest/gc/z/test_zVirtualMemory.cpp Tue May 14 11:23:08 2019 +0530
+++ b/test/hotspot/gtest/gc/z/test_zVirtualMemory.cpp Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 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
@@ -23,26 +23,23 @@
#include "precompiled.hpp"
#include "gc/z/zVirtualMemory.inline.hpp"
-#include "utilities/debug.hpp"
#include "unittest.hpp"
TEST(ZVirtualMemory, split) {
- const size_t PageSize = 2 * M;
-
- ZVirtualMemory mem(0, 10 * PageSize);
+ ZVirtualMemory vmem(0, 10);
- ZVirtualMemory mem_split0 = mem.split(0 * PageSize);
- EXPECT_EQ(mem_split0.size(), 0 * PageSize);
- EXPECT_EQ( mem.size(), 10 * PageSize);
+ ZVirtualMemory vmem0 = vmem.split(0);
+ EXPECT_EQ(vmem0.size(), 0u);
+ EXPECT_EQ(vmem.size(), 10u);
- ZVirtualMemory mem_split1 = mem.split(5u * PageSize);
- EXPECT_EQ(mem_split1.size(), 5 * PageSize);
- EXPECT_EQ( mem.size(), 5 * PageSize);
+ ZVirtualMemory vmem1 = vmem.split(5);
+ EXPECT_EQ(vmem1.size(), 5u);
+ EXPECT_EQ(vmem.size(), 5u);
- ZVirtualMemory mem_split2 = mem.split(5u * PageSize);
- EXPECT_EQ(mem_split2.size(), 5 * PageSize);
- EXPECT_EQ( mem.size(), 0 * PageSize);
+ ZVirtualMemory vmem2 = vmem.split(5);
+ EXPECT_EQ(vmem2.size(), 5u);
+ EXPECT_EQ(vmem.size(), 0u);
- ZVirtualMemory mem_split3 = mem.split(0 * PageSize);
- EXPECT_EQ(mem_split3.size(), 0 * PageSize);
+ ZVirtualMemory vmem3 = vmem.split(0);
+ EXPECT_EQ(vmem3.size(), 0u);
}
--- a/test/hotspot/gtest/gtestMain.cpp Tue May 14 11:23:08 2019 +0530
+++ b/test/hotspot/gtest/gtestMain.cpp Wed May 15 13:54:43 2019 +0530
@@ -231,7 +231,7 @@
#endif // __APPLE__
#else // _WIN32
- char* java_home_var = "_ALT_JAVA_HOME_DIR";
+ const char* java_home_var = "_ALT_JAVA_HOME_DIR";
size_t len = strlen(java_home) + strlen(java_home_var) + 2;
char * envString = new char[len];
sprintf_s(envString, len, "%s=%s", java_home_var, java_home);
--- a/test/hotspot/jtreg/ProblemList-zgc.txt Tue May 14 11:23:08 2019 +0530
+++ b/test/hotspot/jtreg/ProblemList-zgc.txt Wed May 15 13:54:43 2019 +0530
@@ -37,6 +37,5 @@
serviceability/sa/TestClhsdbJstackLock.java 8220624 generic-all
serviceability/sa/TestHeapDumpForInvokeDynamic.java 8220624 generic-all
serviceability/sa/TestHeapDumpForLargeArray.java 8220624 generic-all
-serviceability/sa/TestUniverse.java 8220624 generic-all
serviceability/sa/TestJmapCore.java 8220624 generic-all
serviceability/sa/TestJmapCoreMetaspace.java 8219443 generic-all
--- a/test/hotspot/jtreg/ProblemList.txt Tue May 14 11:23:08 2019 +0530
+++ b/test/hotspot/jtreg/ProblemList.txt Wed May 15 13:54:43 2019 +0530
@@ -41,6 +41,7 @@
# :hotspot_compiler
compiler/ciReplay/TestSAServer.java 8029528 generic-all
+compiler/ciReplay/TestServerVM.java 8223885 generic-all
compiler/codecache/stress/OverloadCompileQueueTest.java 8166554 generic-all
compiler/codegen/Test6896617.java 8193479 generic-all
compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8140405 generic-all
--- a/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsLog.java Tue May 14 11:23:08 2019 +0530
+++ b/test/hotspot/jtreg/gc/g1/TestEagerReclaimHumongousRegionsLog.java Wed May 15 13:54:43 2019 +0530
@@ -71,7 +71,7 @@
// This gives an array of lines containing eager reclaim of humongous regions
// log messages contents after the ":" in the following order for every GC:
- // Humongous Register: a.ams
+ // Region Register: a.ams
// Humongous Total: b
// Humongous Candidate: c
// Humongous Reclaim: d.dms
@@ -79,7 +79,7 @@
// Humongous Regions: f->g
String[] lines = Arrays.stream(output.getStdout().split("\\R"))
- .filter(s -> s.contains("Humongous")).map(s -> s.substring(s.indexOf(LogSeparator) + LogSeparator.length()))
+ .filter(s -> (s.contains("Humongous") || s.contains("Region Register"))).map(s -> s.substring(s.indexOf(LogSeparator) + LogSeparator.length()))
.toArray(String[]::new);
Asserts.assertTrue(lines.length % 6 == 0, "There seems to be an unexpected amount of log messages (total: " + lines.length + ") per GC");
--- a/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java Tue May 14 11:23:08 2019 +0530
+++ b/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java Wed May 15 13:54:43 2019 +0530
@@ -132,6 +132,7 @@
new LogMessageWithLevel("Queue Fixup", Level.DEBUG),
new LogMessageWithLevel("Table Fixup", Level.DEBUG),
new LogMessageWithLevel("Expand Heap After Collection", Level.DEBUG),
+ new LogMessageWithLevel("Region Register", Level.DEBUG),
// Free CSet
new LogMessageWithLevel("Free Collection Set", Level.DEBUG),
new LogMessageWithLevel("Free Collection Set Serial", Level.TRACE),
@@ -139,7 +140,6 @@
new LogMessageWithLevel("Non-Young Free Collection Set", Level.TRACE),
// Humongous Eager Reclaim
new LogMessageWithLevel("Humongous Reclaim", Level.DEBUG),
- new LogMessageWithLevel("Humongous Register", Level.DEBUG),
// Merge PSS
new LogMessageWithLevel("Merge Per-Thread State", Level.DEBUG),
// TLAB handling
--- a/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java Tue May 14 11:23:08 2019 +0530
+++ b/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java Wed May 15 13:54:43 2019 +0530
@@ -47,17 +47,6 @@
{
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions",
"-XX:+UseShenandoahGC",
- "-Xms2m",
- "-Xmx1g",
- "-version");
- OutputAnalyzer output = new OutputAnalyzer(pb.start());
- output.shouldMatch("Initial heap size");
- output.shouldHaveExitValue(1);
- }
-
- {
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions",
- "-XX:+UseShenandoahGC",
"-Xms4m",
"-Xmx1g",
"-version");
@@ -92,18 +81,6 @@
"-XX:+UseShenandoahGC",
"-Xms100m",
"-Xmx1g",
- "-XX:ShenandoahHeapRegionSize=11m",
- "-version");
- OutputAnalyzer output = new OutputAnalyzer(pb.start());
- output.shouldMatch("Invalid -XX:ShenandoahHeapRegionSize option");
- output.shouldHaveExitValue(1);
- }
-
- {
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions",
- "-XX:+UseShenandoahGC",
- "-Xms100m",
- "-Xmx1g",
"-XX:ShenandoahHeapRegionSize=9m",
"-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
@@ -223,18 +200,6 @@
"-XX:+UseShenandoahGC",
"-Xms100m",
"-Xmx1g",
- "-XX:ShenandoahMinRegionSize=11m",
- "-version");
- OutputAnalyzer output = new OutputAnalyzer(pb.start());
- output.shouldMatch("Invalid -XX:ShenandoahMinRegionSize option");
- output.shouldHaveExitValue(1);
- }
-
- {
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions",
- "-XX:+UseShenandoahGC",
- "-Xms100m",
- "-Xmx1g",
"-XX:ShenandoahMinRegionSize=9m",
"-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/gc/z/TestUncommit.java Wed May 15 13:54:43 2019 +0530
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+package gc.z;
+
+/*
+ * @test TestUncommit
+ * @requires vm.gc.Z
+ * @summary Test ZGC uncommit unused memory
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xms128M -Xmx512M -XX:ZUncommitDelay=10 gc.z.TestUncommit true 3
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xms512M -Xmx512M -XX:ZUncommitDelay=10 gc.z.TestUncommit false 1
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xms128M -Xmx512M -XX:ZUncommitDelay=10 -XX:-ZUncommit gc.z.TestUncommit false 1
+ */
+
+import java.util.ArrayList;
+
+public class TestUncommit {
+ private static final int delay = 10; // seconds
+ private static final int allocSize = 200 * 1024 * 1024; // 200M
+ private static final int smallObjectSize = 4 * 1024; // 4K
+ private static final int mediumObjectSize = 2 * 1024 * 1024; // 2M
+ private static final int largeObjectSize = allocSize;
+
+ private static volatile ArrayList<byte[]> keepAlive;
+
+ private static long capacity() {
+ return Runtime.getRuntime().totalMemory();
+ }
+
+ private static void allocate(int objectSize) {
+ keepAlive = new ArrayList<>();
+ for (int i = 0; i < allocSize; i+= objectSize) {
+ keepAlive.add(new byte[objectSize]);
+ }
+ }
+
+ private static void reclaim() {
+ keepAlive = null;
+ System.gc();
+ }
+
+ private static void test(boolean enabled, int objectSize) throws Exception {
+ final var beforeAlloc = capacity();
+
+ // Allocate memory
+ allocate(objectSize);
+
+ final var afterAlloc = capacity();
+
+ // Reclaim memory
+ reclaim();
+
+ // Wait shorter than the uncommit delay
+ Thread.sleep(delay * 1000 / 2);
+
+ final var beforeUncommit = capacity();
+
+ // Wait longer than the uncommit delay
+ Thread.sleep(delay * 1000);
+
+ final var afterUncommit = capacity();
+
+ System.out.println(" Uncommit Enabled: " + enabled);
+ System.out.println(" Uncommit Delay: " + delay);
+ System.out.println(" Object Size: " + objectSize);
+ System.out.println(" Alloc Size: " + allocSize);
+ System.out.println(" Before Alloc: " + beforeAlloc);
+ System.out.println(" After Alloc: " + afterAlloc);
+ System.out.println(" Before Uncommit: " + beforeUncommit);
+ System.out.println(" After Uncommit: " + afterUncommit);
+ System.out.println();
+
+ // Verify
+ if (enabled) {
+ if (beforeUncommit == beforeAlloc) {
+ throw new Exception("Uncommitted too fast");
+ }
+
+ if (afterUncommit >= afterAlloc) {
+ throw new Exception("Uncommitted too slow");
+ }
+
+ if (afterUncommit < beforeAlloc) {
+ throw new Exception("Uncommitted too much");
+ }
+
+ if (afterUncommit > beforeAlloc) {
+ throw new Exception("Uncommitted too little");
+ }
+ } else {
+ if (afterAlloc > beforeUncommit ||
+ afterAlloc > afterUncommit) {
+ throw new Exception("Should not uncommit");
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ final boolean enabled = Boolean.parseBoolean(args[0]);
+ final int iterations = Integer.parseInt(args[1]);
+
+ for (int i = 0; i < iterations; i++) {
+ System.out.println("Iteration " + i);
+ test(enabled, smallObjectSize);
+ test(enabled, mediumObjectSize);
+ test(enabled, largeObjectSize);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/ErrorHandling/ErrorFileOverwriteTest.java Wed May 15 13:54:43 2019 +0530
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, SAP. All rights reserved.
+ * 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 8221738
+ * @summary Test that subsequent crashes will overwrite the file given to -XX:ErrorFile (unless %a is specified
+ * in the error file name)
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * @requires (vm.debug == true)
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+import java.io.*;
+import java.util.regex.Pattern;
+
+public class ErrorFileOverwriteTest {
+
+ private static File findHsErrorFileInOutput(OutputAnalyzer output) {
+
+ String hs_err_file = output.firstMatch("# *(\\S*hs_err_pid.*\\.log)", 1);
+ if(hs_err_file ==null) {
+ throw new RuntimeException("Did not find hs-err file in output.\n");
+ }
+
+ File f = new File(hs_err_file);
+ if (!f.exists()) {
+ throw new RuntimeException("hs-err file missing at "
+ + f.getAbsolutePath() + ".\n");
+ }
+
+ return f;
+
+ }
+
+ private static void scanHsErrorFileForContent(File f, Pattern[] pattern) throws IOException {
+ FileInputStream fis = new FileInputStream(f);
+ BufferedReader br = new BufferedReader(new InputStreamReader(fis));
+ String line = null;
+
+ int currentPattern = 0;
+
+ String lastLine = null;
+ while ((line = br.readLine()) != null && currentPattern < pattern.length) {
+ if (pattern[currentPattern].matcher(line).matches()) {
+ System.out.println("Found: " + line + ".");
+ currentPattern++;
+ }
+ lastLine = line;
+ }
+ br.close();
+
+ if (currentPattern < pattern.length) {
+ throw new RuntimeException("hs-err file incomplete (first missing pattern: " + pattern[currentPattern] + ")");
+ }
+
+ }
+
+ public static void do_test(boolean with_percent_p) throws Exception {
+
+ // Crash twice.
+ //
+ // Second crash should, given an error file Without %p,
+ // overwrite the first file. With %p it should not.
+
+ String errorFileStem = "hs_err_pid_test";
+ String errorFileName = errorFileStem + (with_percent_p ? "%p" : "") + ".log";
+
+ System.out.println("Testing with error file name " + errorFileName + "...");
+
+ System.out.println("First crash...");
+
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-Xmx64M",
+ "-XX:-CreateCoredumpOnCrash",
+ "-XX:ErrorHandlerTest=1",
+ "-XX:ErrorFile=" + errorFileName,
+ "-version");
+
+ OutputAnalyzer output_detail = new OutputAnalyzer(pb.start());
+
+ output_detail.shouldMatch("# A fatal error has been detected by the Java Runtime Environment:.*");
+ output_detail.shouldMatch("# An error report file with more information is saved as:.*");
+ output_detail.shouldMatch("# " + errorFileStem + ".*");
+ System.out.println("First crash: Found expected output on tty. Ok.");
+
+ File f = findHsErrorFileInOutput(output_detail);
+ System.out.println("First crash: Found hs error file at " + f.getAbsolutePath());
+
+ scanHsErrorFileForContent(f, new Pattern[] {
+ Pattern.compile("# *Internal Error.*"),
+ Pattern.compile("Command Line:.*-XX:ErrorHandlerTest=1.*-XX:ErrorFile=" + errorFileStem + ".*")
+ });
+ System.out.println("First crash: hs error content as expected. Ok.");
+
+
+ System.out.println("Second crash...");
+
+ pb = ProcessTools.createJavaProcessBuilder(
+ "-Xmx64M",
+ "-XX:-CreateCoredumpOnCrash",
+ "-XX:ErrorHandlerTest=2", // << now 2
+ "-XX:ErrorFile=" + errorFileName,
+ "-version");
+
+ output_detail = new OutputAnalyzer(pb.start());
+
+ output_detail.shouldMatch("# A fatal error has been detected by the Java Runtime Environment:.*");
+ output_detail.shouldMatch("# An error report file with more information is saved as:.*");
+ output_detail.shouldMatch("# " + errorFileStem + ".*");
+ System.out.println("Second crash: Found expected output on tty. Ok.");
+
+ File f2 = findHsErrorFileInOutput(output_detail);
+ System.out.println("Second crash: Found hs error file at " + f2.getAbsolutePath());
+
+ if (with_percent_p) {
+ if (f2.getAbsolutePath() == f.getAbsolutePath()) {
+ throw new RuntimeException("Unexpected overwriting of error file");
+ }
+ }
+
+ scanHsErrorFileForContent(f2, new Pattern[] {
+ Pattern.compile("# *Internal Error.*"),
+ Pattern.compile("Command Line:.*-XX:ErrorHandlerTest=2.*-XX:ErrorFile=" + errorFileStem + ".*")
+ });
+ System.out.println("Second crash: hs error content as expected. Ok.");
+
+ }
+
+ public static void main(String[] args) throws Exception {
+ do_test(false);
+ do_test(true);
+ }
+
+}
+
+
--- a/test/hotspot/jtreg/runtime/appcds/SharedArchiveConsistency.java Tue May 14 11:23:08 2019 +0530
+++ b/test/hotspot/jtreg/runtime/appcds/SharedArchiveConsistency.java Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2018, 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
@@ -318,7 +318,11 @@
// test, should pass
System.out.println("1. Normal, should pass but may fail\n");
+
String[] execArgs = {"-cp", jarFile, "Hello"};
+ // tests that corrupt contents of the archive need to run with
+ // VerifySharedSpaces enabled to detect inconsistencies
+ String[] verifyExecArgs = {"-XX:+VerifySharedSpaces", "-cp", jarFile, "Hello"};
OutputAnalyzer output = TestCommon.execCommon(execArgs);
@@ -350,9 +354,10 @@
// modify content
System.out.println("\n3. Corrupt Content, should fail\n");
+
copyFile(orgJsaFile, jsa);
modifyJsaContent();
- testAndCheck(execArgs);
+ testAndCheck(verifyExecArgs);
// modify both header and content, test should fail
System.out.println("\n4. Corrupt Header and Content, should fail\n");
@@ -363,19 +368,19 @@
output.shouldContain("The shared archive file has the wrong version");
output.shouldNotContain("Checksum verification failed");
- // delete bytes in data sectoin
- System.out.println("\n5. Delete bytes at begining of data section, should fail\n");
+ // delete bytes in data section
+ System.out.println("\n5. Delete bytes at beginning of data section, should fail\n");
copyFile(orgJsaFile, jsa, true);
- testAndCheck(execArgs);
+ testAndCheck(verifyExecArgs);
- // insert bytes in data sectoin forward
- System.out.println("\n6. Insert bytes at begining of data section, should fail\n");
+ // insert bytes in data section forward
+ System.out.println("\n6. Insert bytes at beginning of data section, should fail\n");
copyFile(orgJsaFile, jsa, false);
- testAndCheck(execArgs);
+ testAndCheck(verifyExecArgs);
System.out.println("\n7. modify Content in random areas, should fail\n");
copyFile(orgJsaFile, jsa);
modifyJsaContentRandomly();
- testAndCheck(execArgs);
+ testAndCheck(verifyExecArgs);
}
}
--- a/test/jdk/java/net/ServerSocket/AcceptCauseFileDescriptorLeak.java Tue May 14 11:23:08 2019 +0530
+++ b/test/jdk/java/net/ServerSocket/AcceptCauseFileDescriptorLeak.java Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -41,6 +41,7 @@
*/
import java.io.IOException;
+import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
@@ -80,7 +81,7 @@
}
}
- final ServerSocket ss = new ServerSocket(0) {
+ final ServerSocket ss = new ServerSocket(0, 0, InetAddress.getLoopbackAddress()) {
public Socket accept() throws IOException {
Socket s = new Socket() {
};
@@ -93,7 +94,7 @@
public void run() {
try {
for (int i = 0; i < REPS; i++) {
- (new Socket("localhost", ss.getLocalPort())).close();
+ (new Socket(InetAddress.getLoopbackAddress(), ss.getLocalPort())).close();
}
} catch (IOException e) {
e.printStackTrace();
--- a/test/jdk/java/net/ServerSocket/UnreferencedSockets.java Tue May 14 11:23:08 2019 +0530
+++ b/test/jdk/java/net/ServerSocket/UnreferencedSockets.java Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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,6 +39,7 @@
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.io.IOException;
+import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketImpl;
@@ -71,8 +72,8 @@
ServerSocket ss;
- Server() throws IOException {
- ss = new ServerSocket(0);
+ Server(InetAddress address) throws IOException {
+ ss = new ServerSocket(0, 0, address);
pendingSockets.add(new NamedWeak(ss, pendingQueue, "serverSocket"));
extractRefs(ss, "serverSocket");
}
@@ -81,7 +82,6 @@
return ss.getLocalPort();
}
-
public void run() {
try {
Socket s = ss.accept();
@@ -111,9 +111,9 @@
public static void main(String args[]) throws Exception {
IPSupport.throwSkippedExceptionIfNonOperational();
-
+ InetAddress lba = InetAddress.getLoopbackAddress();
// Create and close a ServerSocket to warm up the FD count for side effects.
- try (ServerSocket s = new ServerSocket(0)) {
+ try (ServerSocket s = new ServerSocket(0, 0, lba)) {
// no-op; close immediately
s.getLocalPort(); // no-op
}
@@ -122,11 +122,11 @@
listProcFD();
// start a server
- Server svr = new Server();
+ Server svr = new Server(lba);
Thread thr = new Thread(svr);
thr.start();
- Socket s = new Socket("localhost", svr.localPort());
+ Socket s = new Socket(lba, svr.localPort());
pendingSockets.add(new NamedWeak(s, pendingQueue, "clientSocket"));
extractRefs(s, "clientSocket");
--- a/test/jdk/java/net/URL/PerConnectionProxy.java Tue May 14 11:23:08 2019 +0530
+++ b/test/jdk/java/net/URL/PerConnectionProxy.java Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, 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
@@ -25,7 +25,7 @@
* @bug 4920526
* @summary Needs per connection proxy support for URLs
* @modules java.base/sun.net.www
- * @library ../../../sun/net/www/httptest/
+ * @library ../../../sun/net/www/httptest/ /test/lib
* @build ClosedChannelList TestHttpServer HttpTransaction HttpCallback
* @compile PerConnectionProxy.java
* @run main/othervm -Dhttp.proxyHost=inexistant -Dhttp.proxyPort=8080 PerConnectionProxy
@@ -33,7 +33,8 @@
import java.net.*;
import java.io.*;
-import sun.net.www.*;
+
+import jdk.test.lib.net.URIBuilder;
public class PerConnectionProxy implements HttpCallback {
static TestHttpServer server;
@@ -49,12 +50,17 @@
public static void main(String[] args) {
try {
- server = new TestHttpServer (new PerConnectionProxy(), 1, 10, 0);
- ProxyServer pserver = new ProxyServer(InetAddress.getByName("localhost"), server.getLocalPort());
+ InetAddress loopbackAddress = InetAddress.getLoopbackAddress();
+ server = new TestHttpServer(new PerConnectionProxy(), 1, 10, loopbackAddress, 0);
+ ProxyServer pserver = new ProxyServer(loopbackAddress, server.getLocalPort());
// start proxy server
new Thread(pserver).start();
- URL url = new URL("http://localhost:"+server.getLocalPort());
+ URL url = URIBuilder.newBuilder()
+ .scheme("http")
+ .loopback()
+ .port(server.getLocalPort())
+ .toURLUnchecked();
// for non existing proxy expect an IOException
try {
@@ -80,7 +86,9 @@
// for a normal proxy setting expect to see connection
// goes through that proxy
try {
- InetSocketAddress isa = InetSocketAddress.createUnresolved("localhost", pserver.getPort());
+ InetSocketAddress isa = InetSocketAddress.createUnresolved(
+ loopbackAddress.getHostAddress(),
+ pserver.getPort());
Proxy p = new Proxy(Proxy.Type.HTTP, isa);
HttpURLConnection urlc = (HttpURLConnection)url.openConnection (p);
int respCode = urlc.getResponseCode();
@@ -115,7 +123,7 @@
public ProxyServer(InetAddress server, int port) throws IOException {
serverInetAddr = server;
serverPort = port;
- ss = new ServerSocket(0);
+ ss = new ServerSocket(0, 0, InetAddress.getLoopbackAddress());
}
public void run() {
--- a/test/jdk/java/net/URLConnection/Redirect307Test.java Tue May 14 11:23:08 2019 +0530
+++ b/test/jdk/java/net/URLConnection/Redirect307Test.java Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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,11 +24,14 @@
/**
* @test
* @bug 4380568 7095949
+ * @library /test/lib
* @summary HttpURLConnection does not support 307 redirects
*/
import java.io.*;
import java.net.*;
+import jdk.test.lib.net.URIBuilder;
+
class RedirServer extends Thread {
static final int TIMEOUT = 10 * 1000;
@@ -100,12 +103,16 @@
public class Redirect307Test {
public static void main(String[] args) throws Exception {
- ServerSocket sock = new ServerSocket(0);
+ ServerSocket sock = new ServerSocket(0, 0, InetAddress.getLoopbackAddress());
int port = sock.getLocalPort();
RedirServer server = new RedirServer(sock);
server.start();
- URL url = new URL("http://localhost:" + port);
+ URL url = URIBuilder.newBuilder()
+ .scheme("http")
+ .loopback()
+ .port(port)
+ .toURL();
URLConnection conURL = url.openConnection();
conURL.setDoInput(true);
conURL.setAllowUserInteraction(false);
--- a/test/jdk/java/net/URLConnection/RedirectLimit.java Tue May 14 11:23:08 2019 +0530
+++ b/test/jdk/java/net/URLConnection/RedirectLimit.java Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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,6 +24,7 @@
/**
* @test
* @bug 4458085 7095949
+ * @library /test/lib
* @summary Redirects Limited to 5
*/
@@ -35,6 +36,8 @@
import java.io.*;
import java.net.*;
+import jdk.test.lib.net.URIBuilder;
+
class RedirLimitServer extends Thread {
static final int TIMEOUT = 10 * 1000;
static final int NUM_REDIRECTS = 9;
@@ -105,12 +108,16 @@
public class RedirectLimit {
public static void main(String[] args) throws Exception {
- ServerSocket ss = new ServerSocket (0);
+ ServerSocket ss = new ServerSocket(0, 0, InetAddress.getLoopbackAddress());
int port = ss.getLocalPort();
RedirLimitServer server = new RedirLimitServer(ss);
server.start();
- URL url = new URL("http://localhost:" + port);
+ URL url = URIBuilder.newBuilder()
+ .scheme("http")
+ .loopback()
+ .port(port)
+ .toURL();
URLConnection conURL = url.openConnection();
conURL.setDoInput(true);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/text/Collator/RuleBasedCollatorTest.java Wed May 15 13:54:43 2019 +0530
@@ -0,0 +1,233 @@
+/*
+ * 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 4406815 8222969
+ * @summary RuleBasedCollatorTest uses very limited but selected test data
+ * to test basic functionalities provided by RuleBasedCollator.
+ * @run testng/othervm RuleBasedCollatorTest
+ */
+
+import java.text.CollationElementIterator;
+import java.text.CollationKey;
+import java.text.RuleBasedCollator;
+import java.text.Collator;
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Locale;
+
+import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.testng.SkipException;
+import static org.testng.Assert.*;
+
+public class RuleBasedCollatorTest {
+
+ static RuleBasedCollator USC;
+ static String US_RULES;
+
+ @BeforeGroups("USC")
+ public void setup() {
+ Collator c = Collator.getInstance(Locale.US);
+ if (!(c instanceof RuleBasedCollator)) {
+ throw new SkipException("skip tests.");
+ }
+ USC = (RuleBasedCollator) c;
+ US_RULES = USC.getRules();
+ }
+
+
+ @DataProvider(name = "rulesData")
+ Object[][] rulesData() {
+ //Basic Tailor
+ String BASIC_TAILOR_RULES = "< b=c<\u00e6;A,a";
+ String[] BASIC_TAILOR_DATA = {"\u00e6", "b", "a", "c", "A"};
+ String[] BASIC_TAILOR_EXPECTED = {"b", "c", "\u00e6", "A", "a"};
+
+ //Contraction
+ String CONTRACTION_RULES = US_RULES + "& b < ch ,cH, Ch, CH < c ";
+ String[] CONTRACTION_DATA = {"b", "c", "ch", "CH", "Ch", "cH"};
+ String[] CONTRACTION_EXPECTED = {"b", "ch", "cH", "Ch", "CH", "c"};
+
+ //Expansion
+ String EXPANSION_RULES = US_RULES + "& ae = \u00e4 < b";
+ String[] EXPANSION_DATA = {"ad", "af", "\u00e4"};
+ String[] EXPANSION_EXPECTED = {"ad", "\u00e4", "af"};
+
+ //Punctuation
+ String PUNCTUATION_RULES = US_RULES + "< ' ' < '-'";
+ String[] PUNCTUATION_DATA = {"b-w", "b-W", "B-w", "B-W", "bW", "bw",
+ "Bw", "BW", "b w", "b W", "B w", "B W"};
+ String[] PUNCTUATION_EXPECTED = {"bw", "bW", "Bw", "BW", "b w", "b W",
+ "B w", "B W", "b-w", "b-W", "B-w", "B-W"};
+
+ return new Object[][] {
+ {BASIC_TAILOR_RULES, BASIC_TAILOR_DATA, BASIC_TAILOR_EXPECTED},
+ {CONTRACTION_RULES, CONTRACTION_DATA, CONTRACTION_EXPECTED},
+ {EXPANSION_RULES, EXPANSION_DATA, EXPANSION_EXPECTED},
+ {PUNCTUATION_RULES, PUNCTUATION_DATA, PUNCTUATION_EXPECTED}
+ };
+ }
+
+ @Test(dataProvider = "rulesData", groups = "USC")
+ public void testRules(String rules, String[] testData, String[] expected)
+ throws ParseException {
+ Arrays.sort(testData, new RuleBasedCollator(rules));
+ assertEquals(testData, expected);
+
+ }
+
+ @DataProvider(name = "FrenchSecondarySort")
+ Object[][] FrenchSecondarySort() {
+ return new Object[][] {
+ { "\u0061\u00e1\u0061", "\u00e1\u0061\u0061", 1 },
+ //{"\u0061\u00e1", "\u00e1\u0041", 1}, //JDK-4406815
+ //{"\u00e1\u0041", "\u0061\u00e1", -1}, //JDK-4406815
+ {"\u1ea0a", "\u1ea2A", -1}, //case ignore
+ { "\u1ea0b", "\u1ea2A", 1 }, //primary overwrite
+ { "\u1e15", "\u1e1d", -1 }, //ignore sec diacritic
+ { "a", "\u1ea1", -1 } };
+ }
+
+ @Test(dataProvider = "FrenchSecondarySort", groups = "USC")
+ public void testFrenchSecondarySort(String sData, String tData,
+ int expected) throws ParseException {
+ String french_rule = "@";
+ String rules = US_RULES + french_rule;
+ RuleBasedCollator rc = new RuleBasedCollator(rules);
+ int result = rc.compare(sData, tData);
+ assertEquals(expected, result);
+ }
+
+ @DataProvider(name = "ThaiLaoVowelConsonantSwapping")
+ Object[][] ThaiLaoVowelConsonantSwapping() {
+ return new Object[][] {{"\u0e44\u0e01", "\u0e40\u0e2e", -1},//swap
+ {"\u0e2e\u0e40", "\u0e01\u0e44", 1},//no swap
+ {"\u0e44\u0061", "\u0e40\u0081", 1}//no swap
+ };
+ }
+
+ @Test(dataProvider = "ThaiLaoVowelConsonantSwapping", groups = "USC")
+ public void testThaiLaoVowelConsonantSwapping(String sData, String tData,
+ int expected) throws ParseException {
+ String thai_rule = "& Z < \u0e01 < \u0e2e <\u0e40 < \u0e44!";
+ String rules = US_RULES + thai_rule;
+ RuleBasedCollator rc = new RuleBasedCollator(rules);
+ int result = rc.compare(sData, tData);
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testIgnorableCharacter() throws ParseException {
+ String rule = "=f<a<c";
+ RuleBasedCollator rc = new RuleBasedCollator(rule);
+ CollationElementIterator iter = rc.getCollationElementIterator("f");
+ int element = iter.next();
+ int primary = iter.primaryOrder(element);
+ assertEquals(primary, 0);
+ }
+
+ @DataProvider(name = "Normalization")
+ Object[][] Normalization() {
+ return new Object[][] {
+ //micro sign has no canonical decomp mapping
+ // 0:NO_Decomposition;
+ // 1:CANONICAL_Decomposition;
+ // 2:FULL_Decomposition
+ {"\u00b5", "\u03BC", 0, -1},
+ {"\u00b5", "\u03BC", 1, -1},
+ {"\u00b5", "\u03BC", 2, 0}
+ };
+ }
+
+ @Test(dataProvider = "Normalization", groups = "USC")
+ public void testNormalization(String sData, String tData, int decomp,
+ int result) {
+ RuleBasedCollator rc = (RuleBasedCollator)USC.clone();
+ rc.setDecomposition(decomp);
+ assertEquals(rc.compare(sData, tData), result);
+ }
+
+ @Test
+ public void testEquality() throws ParseException {
+ String rule1 = "<a=b";
+ RuleBasedCollator rc1= new RuleBasedCollator(rule1);
+ //test equals()
+ assertTrue(rc1.equals(new RuleBasedCollator(rule1)));
+
+ //test semantic equality
+ String[] array1 = {"b", "c", "a"};
+ String[] array2 = Arrays.copyOf(array1, array1.length);
+ String[] expected = {"b", "a", "c"};
+ String rule2 = "<b=a";
+ RuleBasedCollator rc2= new RuleBasedCollator(rule2);
+
+ Arrays.sort(array1, rc1);
+ Arrays.sort(array2, rc2);
+ assertEquals(array1, array2);
+ assertEquals(array1, expected);
+ }
+
+ @Test
+ public void testBasicParsingOrder() throws ParseException {
+ String rule1 = "< a < b & a < c";
+ String rule2 = "< a < c & a < b";
+ String rule3 = "< a < b < c";
+ String s = "abc";
+ RuleBasedCollator c1 = new RuleBasedCollator(rule1);
+ RuleBasedCollator c2 = new RuleBasedCollator(rule2);
+ RuleBasedCollator c3 = new RuleBasedCollator(rule3);
+ CollationKey k1 = c1.getCollationKey(s);
+ CollationKey k2 = c2.getCollationKey(s);
+ CollationKey k3 = c3.getCollationKey(s);
+ //rule1 should not equals to rule2
+ assertEquals(k1.compareTo(k2) == 0, false);
+
+ //rule2 should equals to rule3
+ assertEquals(k2.compareTo(k3) == 0, true);
+ }
+
+ @DataProvider(name = "ParseData")
+ Object[][] ParseData() {
+ return new Object[][] {
+ {""},
+ {"a < b"},
+ {"< a-b < c"},
+ {"< ,a"},
+ {"< a < b & c < d"}
+ };
+ }
+
+ @Test(dataProvider = "ParseData",
+ expectedExceptions = ParseException.class)
+ public void testParseException(String rule) throws ParseException{
+ new RuleBasedCollator(rule);
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testNullParseException() throws ParseException{
+ new RuleBasedCollator(null);
+ }
+}
--- a/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java Tue May 14 11:23:08 2019 +0530
+++ b/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -25,7 +25,7 @@
* @test
* @bug 8132734 8194070
* @summary Test the System properties for JarFile that support multi-release jar files
- * @library /lib/testlibrary/java/util/jar
+ * @library /lib/testlibrary/java/util/jar /test/lib
* @modules jdk.jartool
* jdk.compiler
* jdk.httpserver
@@ -44,9 +44,12 @@
*/
import java.io.IOException;
+import java.net.InetAddress;
import java.net.URL;
import java.net.URLClassLoader;
+import jdk.test.lib.net.URIBuilder;
+
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
@@ -57,7 +60,7 @@
@BeforeClass
public void initialize() throws Exception {
- server = new SimpleHttpServer();
+ server = new SimpleHttpServer(InetAddress.getLoopbackAddress());
server.start();
super.initialize();
}
@@ -65,7 +68,8 @@
@Override
protected void initializeClassLoader() throws Exception {
URL[] urls = new URL[]{
- new URL("http://localhost:" + server.getPort() + "/multi-release.jar")
+ URIBuilder.newBuilder().scheme("http").port(server.getPort()).loopback()
+ .path("/multi-release.jar").toURL(),
};
cldr = new URLClassLoader(urls);
// load any class, Main is convenient and in the root entries
--- a/test/jdk/jdk/nio/zipfs/ZipFSTester.java Tue May 14 11:23:08 2019 +0530
+++ b/test/jdk/jdk/nio/zipfs/ZipFSTester.java Wed May 15 13:54:43 2019 +0530
@@ -228,7 +228,7 @@
Files.newInputStream(parent);
throw new RuntimeException("Failed");
} catch (FileSystemException e) {
- e.printStackTrace(); // expected fse
+ // expected fse
}
// rmdirs
@@ -420,7 +420,15 @@
static Object[][] getEntries() {
Object[][] entries = new Object[10 + rdm.nextInt(20)][3];
- for (int i = 0; i < entries.length; i++) {
+ // first entries shall test the corner case of 0 bytes of data
+ entries[0][0] = "entries" + 0;
+ entries[0][1] = METHOD_STORED;
+ entries[0][2] = new byte[0];
+ entries[1][0] = "entries" + 1;
+ entries[1][1] = METHOD_DEFLATED;
+ entries[1][2] = new byte[0];
+ // the rest is random data
+ for (int i = 2; i < entries.length; i++) {
entries[i][0] = "entries" + i;
entries[i][1] = rdm.nextInt(10) % 2 == 0 ?
METHOD_STORED : METHOD_DEFLATED;
--- a/test/jdk/lib/testlibrary/java/util/jar/SimpleHttpServer.java Tue May 14 11:23:08 2019 +0530
+++ b/test/jdk/lib/testlibrary/java/util/jar/SimpleHttpServer.java Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 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
@@ -26,6 +26,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -42,13 +43,19 @@
private static final Path multirelease = Paths.get(userdir, "multi-release.jar");
private final HttpServer server;
+ private final InetAddress address;
public SimpleHttpServer() throws IOException {
+ this(null);
+ }
+
+ public SimpleHttpServer(InetAddress addr) throws IOException {
+ address = addr;
server = HttpServer.create();
}
public void start() throws IOException {
- server.bind(new InetSocketAddress(0), 0);
+ server.bind(new InetSocketAddress(address, 0), 0);
server.createContext("/multi-release.jar", t -> {
try (InputStream is = t.getRequestBody()) {
is.readAllBytes(); // probably not necessary to consume request
--- a/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java Tue May 14 11:23:08 2019 +0530
+++ b/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 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
@@ -61,7 +61,7 @@
static int count = 0;
public static void main(String[] args) throws Exception {
try {
- server = new ServerSocket (0);
+ server = new ServerSocket(0, 0, InetAddress.getLoopbackAddress());
int port = server.getLocalPort ();
new Thread(new RetryUponTimeout()).start ();
--- a/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java Tue May 14 11:23:08 2019 +0530
+++ b/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -25,7 +25,7 @@
* @test
* @bug 8132734 8144062 8159785 8194070
* @summary Test that URL connections to multi-release jars can be runtime versioned
- * @library /lib/testlibrary/java/util/jar
+ * @library /lib/testlibrary/java/util/jar /test/lib
* @modules jdk.compiler
* jdk.httpserver
* jdk.jartool
@@ -38,7 +38,11 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.net.InetAddress;
import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
@@ -47,6 +51,8 @@
import java.util.Enumeration;
import java.util.jar.JarFile;
+import jdk.test.lib.net.URIBuilder;
+
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
@@ -68,7 +74,7 @@
creator.buildMultiReleaseJar();
creator.buildSignedMultiReleaseJar();
- server = new SimpleHttpServer();
+ server = new SimpleHttpServer(InetAddress.getLoopbackAddress());
server.start();
}
@@ -167,9 +173,9 @@
{"unsigned", new URL("jar:file:" + unsigned + "!/")},
{"signed", new URL("jar:file:" + signed + "!/")},
// external jar received via http protocol
- {"http", new URL("jar:http://localhost:" + server.getPort() + "/multi-release.jar!/")},
- {"http", new URL("http://localhost:" + server.getPort() + "/multi-release.jar")},
-
+ {"http", toHttpJarURL(server.getPort(), "/multi-release.jar", "!/")},
+ {"http", URIBuilder.newBuilder().scheme("http").port(server.getPort())
+ .loopback().path("/multi-release.jar").toURL()},
};
}
@@ -220,6 +226,18 @@
cldr.close();
}
+ private static URL toHttpJarURL(int port, String jar, String file)
+ throws MalformedURLException, URISyntaxException {
+ assert file.startsWith("!/");
+ URI httpURI = URIBuilder.newBuilder()
+ .scheme("http")
+ .loopback()
+ .port(port)
+ .path(jar)
+ .build();
+ return new URL("jar:" + httpURI + file);
+ }
+
private boolean readAndCompare(URL url, String match) throws Exception {
boolean result;
// necessary to do it this way, instead of openStream(), so we can
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/T8215470/BadEnclosingMethodAttrTest.java Wed May 15 13:54:43 2019 +0530
@@ -0,0 +1,54 @@
+/*
+ * 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 8215470
+ * @summary Bad EnclosingMethod attribute on classes declared in lambdas
+ * @modules jdk.compiler/com.sun.tools.javac.util
+ */
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import com.sun.tools.javac.util.Assert;
+
+public class BadEnclosingMethodAttrTest<T> {
+ protected BadEnclosingMethodAttrTest() {
+ Assert.check(getClass().getEnclosingMethod().toString().equals("static void BadEnclosingMethodAttrTest.lambdaScope(java.lang.Object)"));
+ Type typeFromEnclosingMethod = getClass().getEnclosingMethod().getGenericParameterTypes()[0];
+ ParameterizedType paramType = (ParameterizedType) getClass().getGenericSuperclass();
+ Type typeFromGenericClass = paramType.getActualTypeArguments()[0];
+ Assert.check(typeFromEnclosingMethod.equals(typeFromGenericClass));
+ }
+
+ static <X> void lambdaScope(X x) {
+ Runnable r = () -> {
+ new BadEnclosingMethodAttrTest<X>() {};
+ };
+ r.run();
+ }
+
+ public static void main(final String[] args) {
+ lambdaScope("");
+ }
+}
--- a/test/langtools/tools/javac/classfiles/attributes/EnclosingMethod/EnclosingMethodTest.java Tue May 14 11:23:08 2019 +0530
+++ b/test/langtools/tools/javac/classfiles/attributes/EnclosingMethod/EnclosingMethodTest.java Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, 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
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8042931
+ * @bug 8042931 8215470
* @summary Checking EnclosingMethod attribute of anonymous/local class.
* @library /tools/lib /tools/javac/lib ../lib
* @modules jdk.compiler/com.sun.tools.javac.api
@@ -245,7 +245,7 @@
// anonymous and local classes in lambda
@ExpectedEnclosingMethod(
info = "EnclosingLambda in EnclosingMethodTest",
- enclosingMethod = "lambda",
+ enclosingMethod = "<init>",
enclosingClazz = EnclosingMethodTest.class
)
class EnclosingLambda {
@@ -325,7 +325,7 @@
// anonymous and local classes in lambda
@ExpectedEnclosingMethod(
info = "EnclosingLambda in notEnclosing01",
- enclosingMethod = "lambda",
+ enclosingMethod = "<init>",
enclosingClazz = notEnclosing01.class
)
class EnclosingLambda {
@@ -382,7 +382,7 @@
// anonymous and local classes in lambda
@ExpectedEnclosingMethod(
info = "EnclosingLambda in notEnclosing02",
- enclosingMethod = "lambda",
+ enclosingMethod = "<clinit>",
enclosingClazz = notEnclosing02.class
)
class EnclosingLambda {
@@ -460,7 +460,7 @@
// anonymous and local classes in lambda
@ExpectedEnclosingMethod(
info = "EnclosingLambda in notEnclosing03",
- enclosingMethod = "lambda",
+ enclosingMethod = "<init>",
enclosingClazz = notEnclosing03.class
)
class EnclosingLambda {
@@ -517,7 +517,7 @@
// anonymous and local classes in lambda
@ExpectedEnclosingMethod(
info = "EnclosingLambda in notEnclosing04",
- enclosingMethod = "lambda",
+ enclosingMethod = "<clinit>",
enclosingClazz = notEnclosing04.class
)
class EnclosingLambda {
--- a/test/langtools/tools/javac/lambda/LambdaInnerTypeVarReflect.java Tue May 14 11:23:08 2019 +0530
+++ b/test/langtools/tools/javac/lambda/LambdaInnerTypeVarReflect.java Wed May 15 13:54:43 2019 +0530
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -77,7 +77,7 @@
String javapOut = sw.toString();
assertTrue(javapOut.contains(innerName));
- assertTrue(!javapOut.contains("RRRRR"));
+ assertTrue(javapOut.contains("RRRRR"));
}
public static void main(String[] args) throws IOException {
--- a/test/micro/org/openjdk/bench/java/net/SocketReadWrite.java Tue May 14 11:23:08 2019 +0530
+++ b/test/micro/org/openjdk/bench/java/net/SocketReadWrite.java Wed May 15 13:54:43 2019 +0530
@@ -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
@@ -22,86 +22,194 @@
*/
package org.openjdk.bench.java.net;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+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.TearDown;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
-import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
-import org.openjdk.jmh.annotations.BenchmarkMode;
-import org.openjdk.jmh.annotations.Benchmark;
-import org.openjdk.jmh.annotations.Mode;
-import org.openjdk.jmh.annotations.OutputTimeUnit;
-import org.openjdk.jmh.annotations.Scope;
-import org.openjdk.jmh.annotations.Setup;
-import org.openjdk.jmh.annotations.State;
-import org.openjdk.jmh.annotations.TearDown;
-
/**
- * Tests the overheads of I/O API.
- * This test is known to depend heavily on network conditions and paltform.
+ * Benchmark socket read/write.
+ *
*/
@BenchmarkMode(Mode.Throughput)
-@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Thread)
public class SocketReadWrite {
- private OutputStream os;
- private InputStream is;
- private ServerSocket ss;
- private Socket s1, s2;
- private ReadThread rt;
+ static final InetAddress address = InetAddress.getLoopbackAddress();
+ public static final int TIMEOUT = 10000;
+
+ static class EchoServer implements Runnable {
+ // EchoServer is implemented to execute the same amount echo threads as benchmarking threads are running
+
+ final ServerSocket ss;
+ final int port;
+ final CountDownLatch startedLatch;
+ final int size;
+ final boolean timeout;
+ List<ServerThread> threads = new ArrayList<>();
+ volatile boolean isDone = false;
+
+ public EchoServer(CountDownLatch await, int size, boolean timeout) throws IOException {
+ this.size = size;
+ this.timeout = timeout;
+ ss = new ServerSocket(0);
+ port = ss.getLocalPort();
+ this.startedLatch = await;
+ }
+
+ @Override
+ public void run() {
+ startedLatch.countDown();
+ while (!isDone) {
+ try {
+ Socket s = ss.accept();
+ s.setTcpNoDelay(true);
+ if (timeout) {
+ s.setSoTimeout(TIMEOUT);
+ }
+ ServerThread st = new ServerThread(s, size);
+ threads.add(st);
+ new Thread(st).start();
+ } catch (IOException e) {
+ if (!isDone) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ synchronized void close() throws IOException {
+ if (!isDone) {
+ isDone = true;
+ ss.close();
+ for (ServerThread st : threads) {
+ st.close();
+ }
+ }
+ }
+
+ static EchoServer instance = null;
+
+ static synchronized EchoServer startServer(int size, boolean timeout) throws IOException {
+ if (instance == null) {
+ CountDownLatch started = new CountDownLatch(1);
+ EchoServer s = new EchoServer(started, size, timeout);
+ new Thread(s).start();
+ try {
+ started.await(); // wait until server thread started
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ instance = s;
+ }
+ return instance;
+ }
+
+ static class ServerThread implements Runnable {
+
+ final Socket s;
+ final InputStream in;
+ final OutputStream out;
+ final int size;
+ volatile boolean isDone = false;
+
+ ServerThread(Socket s, int size) throws IOException {
+ this.s = s;
+ this.size = size;
+ in = s.getInputStream();
+ out = s.getOutputStream();
+ }
+
+ @Override
+ public void run() {
+ byte[] a = new byte[size];
+ while (!isDone) {
+ try {
+ readN(a, size, this.in);
+ out.write(a);
+ } catch (IOException e) {
+ if (!isDone) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public void close() throws IOException {
+ isDone = true;
+ s.close();
+ }
+
+ }
+ }
+
+ static void readN(byte[] array, int size, InputStream in) throws IOException {
+ int nread = 0;
+ while (size > 0) {
+ int n = in.read(array, nread, size);
+ if (n < 0) throw new RuntimeException();
+ nread += n;
+ size -= n;
+ }
+ }
+
+ EchoServer server;
+
+ @Param({"1", "1024", "8192", "64000", "128000"})
+ public int size;
+
+ @Param({"false", "true"})
+ public boolean timeout;
+
+ Socket s;
+ InputStream in;
+ OutputStream out;
+ byte[] array;
@Setup
- public void beforeRun() throws IOException {
- InetAddress iaddr = InetAddress.getLocalHost();
-
- ss = new ServerSocket(0);
- s1 = new Socket(iaddr, ss.getLocalPort());
- s2 = ss.accept();
-
- os = s1.getOutputStream();
- is = s2.getInputStream();
-
- rt = new ReadThread(is);
- rt.start();
+ public void setup() throws IOException {
+ server = EchoServer.startServer(size, timeout);
+ int port = server.port;
+ s = new Socket(address, port);
+ s.setTcpNoDelay(true);
+ if (timeout) {
+ s.setSoTimeout(TIMEOUT);
+ // 10 seconds times is quite large and never will happen (for microbenchmarking),
+ // but it's required since other paths inside SocketImpl are involved
+ }
+ in = s.getInputStream();
+ out = s.getOutputStream();
+ array = new byte[size];
+ ThreadLocalRandom.current().nextBytes(array);
}
@TearDown
- public void afterRun() throws IOException, InterruptedException {
- os.write(0);
- os.close();
- is.close();
- s1.close();
- s2.close();
- ss.close();
- rt.join();
+ public void tearDown() throws IOException {
+ server.close();
+ s.close();
}
@Benchmark
- public void test() throws IOException {
- os.write((byte) 4711);
+ public void echo() throws IOException {
+ out.write(array);
+ readN(array, size, in);
}
-
- static class ReadThread extends Thread {
- private InputStream is;
-
- public ReadThread(InputStream is) {
- this.is = is;
- }
-
- public void run() {
- try {
- while (is.read() > 0);
- } catch (SocketException ex) {
- // ignore - most likely "socket closed", which means shutdown
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
}