--- a/.hgtags-top-repo Tue May 07 13:13:12 2013 -0700
+++ b/.hgtags-top-repo Wed Jul 05 18:53:57 2017 +0200
@@ -209,3 +209,4 @@
7fc358f5943676b82f1dccd3152b1ac07d92e38b jdk8-b85
df9b5240f0a76c91cfe1a5b39da4d08df56e05be jdk8-b86
b9415faa7066a4d3b16d466556d5428446918d95 jdk8-b87
+e1a929afcfc492470d50be0b6b0e8dc77d3760b9 jdk8-b88
--- a/common/makefiles/NativeCompilation.gmk Tue May 07 13:13:12 2013 -0700
+++ b/common/makefiles/NativeCompilation.gmk Wed Jul 05 18:53:57 2017 +0200
@@ -411,6 +411,8 @@
$1_EXTRA_LDFLAGS+="-implib:$$($1_OBJECT_DIR)/$$($1_LIBRARY).lib"
endif
+ $1_EXTRA_LDFLAGS_SUFFIX += $(GLOBAL_LDFLAGS_SUFFIX)
+
ifneq (,$$($1_DEBUG_SYMBOLS))
ifeq ($(ENABLE_DEBUG_SYMBOLS), true)
ifeq ($(OPENJDK_TARGET_OS), windows)
@@ -549,6 +551,8 @@
endif
endif
+ $1_EXTRA_LDFLAGS_SUFFIX += $(GLOBAL_LDFLAGS_SUFFIX)
+
$$($1_TARGET) : $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_GEN_MANIFEST)
$$(call LINKING_EXE_MSG,$$($1_BASENAME))
$$($1_LDEXE) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $(EXE_OUT_OPTION)$$($1_TARGET) \
--- a/common/makefiles/javadoc/CORE_PKGS.gmk Tue May 07 13:13:12 2013 -0700
+++ b/common/makefiles/javadoc/CORE_PKGS.gmk Wed Jul 05 18:53:57 2017 +0200
@@ -142,6 +142,7 @@
java.util.prefs \
java.util.regex \
java.util.spi \
+ java.util.stream \
java.util.zip \
javax.accessibility \
javax.activation \
--- a/common/makefiles/javadoc/Javadoc.gmk Tue May 07 13:13:12 2013 -0700
+++ b/common/makefiles/javadoc/Javadoc.gmk Wed Jul 05 18:53:57 2017 +0200
@@ -390,6 +390,17 @@
$(call OptionPair,-tag,specdefault:X) ; \
$(call OptionPair,-tag,Note:X) ; \
$(call OptionPair,-tag,ToDo:X) ; \
+ $(call OptionPair,-tag,apiNote:a:API Note:) ; \
+ $(call OptionPair,-tag,implSpec:a:Implementation Requirements:) ; \
+ $(call OptionPair,-tag,implNote:a:Implementation Note:) ; \
+ $(call OptionPair,-tag,param) ; \
+ $(call OptionPair,-tag,return) ; \
+ $(call OptionPair,-tag,throws) ; \
+ $(call OptionPair,-tag,since) ; \
+ $(call OptionPair,-tag,version) ; \
+ $(call OptionPair,-tag,serialData) ; \
+ $(call OptionPair,-tag,factory) ; \
+ $(call OptionPair,-tag,see) ; \
$(call OptionPair,-tag,$(TAG_JLS)) ; \
$(call OptionOnly,-splitIndex) ; \
$(call OptionPair,-overview,$(COREAPI_OVERVIEW)) ; \
--- a/hotspot/.hgtags Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/.hgtags Wed Jul 05 18:53:57 2017 +0200
@@ -337,3 +337,5 @@
d4c2667846607042370760e23f64c3ab9350e60d jdk8-b87
01d5f04e64dc2d64625b2db2056f5ed4de918a45 hs25-b29
c4af77d2045476c56fbf3f914b336bb1b7cd18af hs25-b30
+8482058e74bc8c1a890e6f3be3eff192dba6ce67 jdk8-b88
+4ec91349972255650f97bedfd07e6423e02428cf hs25-b31
--- a/hotspot/agent/doc/c2replay.html Tue May 07 13:13:12 2013 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-<html>
-<head>
-<title>
-C2 Replay
-</title>
-</head>
-<body>
-
-<h1>C2 compiler replay</h1>
-<p>
-The C2 compiler replay is a function to repeat the compiling process from a crashed java process in compiled method<br>
-This function only exists in debug version of VM
-</p>
-<h2>Usage</h2>
-<pre>
-First, use SA to attach to the core file, if suceeded, do
- clhsdb>dumpreplaydata <address> | -a | <thread_id> [> replay.txt]
- create file replay.txt, address is address of Method, or nmethod(CodeBlob)
- clhsdb>buildreplayjars [all | boot | app]
- create files:
- all:
- app.jar, boot.jar
- boot:
- boot.jar
- app:
- app.jar
- exit SA now.
-Second, use the obtained replay text file, replay.txt and jar files, app.jar and boot.jar, using debug version of java
- java -Xbootclasspath/p:boot.jar -cp app.jar -XX:ReplayDataFile=<datafile> -XX:+ReplayCompiles ....
- This will replay the compiling process.
-
- With ReplayCompiles, the replay will recompile all the methods in app.jar, and in boot.jar to emulate the process in java app.
-
-notes:
- 1) Most time, we don't need the boot.jar which is the classes loaded from JDK. It will be only modified when an agent(JVMDI) is running and modifies the classes.
- 2) If encounter error as "<flag>" not found, that means the SA is using a VMStructs which is different from the one with corefile. In this case, SA has a utility tool vmstructsdump which is located at agent/src/os/<os>/proc/<os_platform>
-
- Use this tool to dump VM type library:
- vmstructsdump libjvm.so > <type_name>.db
-
- set env SA_TYPEDB=<type_name>.db (refer different shell for set envs)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/doc/cireplay.html Wed Jul 05 18:53:57 2017 +0200
@@ -0,0 +1,41 @@
+<html>
+<head>
+<title>
+Replay
+</title>
+</head>
+<body>
+
+<h1>Compiler replay</h1>
+<p>
+The compiler replay is a function to repeat the compiling process from a crashed java process in compiled method<br>
+This function only exists in debug version of VM
+</p>
+<h2>Usage</h2>
+<pre>
+First, use SA to attach to the core file, if succeeded, do
+ hsdb> dumpreplaydata <address> | -a | <thread_id> [> replay.txt]
+ create file replay.txt, address is address of Method, or nmethod(CodeBlob)
+ hsdb> buildreplayjars [all | boot | app]
+ create files:
+ all:
+ app.jar, boot.jar
+ boot:
+ boot.jar
+ app:
+ app.jar
+ exit SA now.
+Second, use the obtained replay text file, replay.txt and jar files, app.jar and boot.jar, using debug version of java
+ java -Xbootclasspath/p:boot.jar -cp app.jar -XX:ReplayDataFile=<datafile> -XX:+ReplayCompiles ....
+ This will replay the compiling process.
+
+ With ReplayCompiles, the replay will recompile all the methods in app.jar, and in boot.jar to emulate the process in java app.
+
+notes:
+ 1) Most time, we don't need the boot.jar which is the classes loaded from JDK. It will be only modified when an agent(JVMDI) is running and modifies the classes.
+ 2) If encounter error as "<flag>" not found, that means the SA is using a VMStructs which is different from the one with corefile. In this case, SA has a utility tool vmstructsdump which is located at agent/src/os/<os>/proc/<os_platform>
+
+ Use this tool to dump VM type library:
+ vmstructsdump libjvm.so > <type_name>.db
+
+ set env SA_TYPEDB=<type_name>.db (refer different shell for set envs)
--- a/hotspot/agent/doc/clhsdb.html Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/agent/doc/clhsdb.html Wed Jul 05 18:53:57 2017 +0200
@@ -15,7 +15,7 @@
<p>
There is also JavaScript based SA command line interface called <a href="jsdb.html">jsdb</a>.
But, CLHSDB supports Unix shell-like (or dbx/gdb-like) command line interface with
-support for output redirection/appending (familiar >, >>), command history and so on.
+support for output redirection/appending (familiar >, >>), command history and so on.
Each CLHSDB command can have zero or more arguments and optionally end with output redirection
(or append) to a file. Commands may be stored in a file and run using <b>source</b> command.
<b>help</b> command prints usage message for all supported commands (or a specific command)
@@ -49,7 +49,7 @@
dumpheap [ file ] <font color="red">dump heap in hprof binary format</font>
dumpideal -a | id <font color="red">dump ideal graph like debug flag -XX:+PrintIdeal</font>
dumpilt -a | id <font color="red">dump inline tree for C2 compilation</font>
- dumpreplaydata <address> | -a | <thread_id> [>replay.txt] <font color="red">dump replay data into a file</font>
+ dumpreplaydata <address> | -a | <thread_id> [>replay.txt] <font color="red">dump replay data into a file</font>
echo [ true | false ] <font color="red">turn on/off command echo mode</font>
examine [ address/count ] | [ address,address] <font color="red">show contents of memory from given address</font>
field [ type [ name fieldtype isStatic offset address ] ] <font color="red">print info about a field of HotSpot type</font>
@@ -96,11 +96,11 @@
<h3>JavaScript integration</h3>
-<p>Few CLHSDB commands are already implemented in JavaScript. It is possible to extend CLHSDB command set
+<p>Few CLHSDB commands are already implemented in JavaScript. It is possible to extend CLHSDB command set
by implementing more commands in a JavaScript file and by loading it by <b>jsload</b> command. <b>jseval</b>
command may be used to evaluate arbitrary JavaScript expression from a string. Any JavaScript function
may be exposed as a CLHSDB command by registering it using JavaScript <b><code>registerCommand</code></b>
-function. This function accepts command name, usage and name of the JavaScript implementation function
+function. This function accepts command name, usage and name of the JavaScript implementation function
as arguments.
</p>
@@ -127,11 +127,11 @@
</code>
</pre>
-<h3>C2 Compilation Replay</h3>
+<h3>Compilation Replay</h3>
<p>
When a java process crashes in compiled method, usually a core file is saved.
-The C2 replay function can reproduce the compiling process in the core.
-<a href="c2replay.html">c2replay.html</a>
+The replay function can reproduce the compiling process in the core.
+<a href="cireplay.html">cireplay.html</a>
</body>
</html>
--- a/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m Wed Jul 05 18:53:57 2017 +0200
@@ -204,7 +204,7 @@
jstring objectName, jstring symbolName)
{
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
- if (ph->core != NULL) {
+ if (ph != NULL && ph->core != NULL) {
return lookupByNameIncore(env, ph, this_obj, objectName, symbolName);
}
@@ -238,10 +238,13 @@
const char* sym = NULL;
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
- sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);
- if (sym == NULL) return 0;
- return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID,
+ if (ph != NULL && ph->core != NULL) {
+ sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);
+ if (sym == NULL) return 0;
+ return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID,
(*env)->NewStringUTF(env, sym), (jlong)offset);
+ }
+ return 0;
}
/** called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0 */
@@ -279,7 +282,7 @@
jbyteArray array;
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
- if (ph->core != NULL) {
+ if (ph != NULL && ph->core != NULL) {
return readBytesFromCore(env, ph, this_obj, addr, numBytes);
}
@@ -394,9 +397,9 @@
/* For core file only, called from
* Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0
*/
-jlongArray getThreadIntegerRegisterSetFromCore(JNIEnv *env, jobject this_obj, long lwp_id) {
+jlongArray getThreadIntegerRegisterSetFromCore(JNIEnv *env, jobject this_obj, long lwp_id, struct ps_prochandle* ph) {
if (!_threads_filled) {
- if (!fill_java_threads(env, this_obj, get_proc_handle(env, this_obj))) {
+ if (!fill_java_threads(env, this_obj, ph)) {
throw_new_debugger_exception(env, "Failed to fill in threads");
return 0;
} else {
@@ -409,7 +412,6 @@
jlongArray array;
jlong *regs;
- struct ps_prochandle* ph = get_proc_handle(env, this_obj);
if (get_lwp_regs(ph, lwp_id, &gregs) != true) {
THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0);
}
@@ -521,8 +523,8 @@
print_debug("getThreadRegisterSet0 called\n");
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
- if (ph->core != NULL) {
- return getThreadIntegerRegisterSetFromCore(env, this_obj, thread_id);
+ if (ph != NULL && ph->core != NULL) {
+ return getThreadIntegerRegisterSetFromCore(env, this_obj, thread_id, ph);
}
kern_return_t result;
@@ -705,8 +707,8 @@
task_t gTask = 0;
result = task_for_pid(mach_task_self(), jpid, &gTask);
if (result != KERN_SUCCESS) {
- print_error("attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result);
- THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
+ print_error("attach: task_for_pid(%d) failed: '%s' (%d)\n", (int)jpid, mach_error_string(result), result);
+ THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process. Could be caused by an incorrect pid or lack of privileges.");
}
putTask(env, this_obj, gTask);
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java Wed Jul 05 18:53:57 2017 +0200
@@ -93,10 +93,11 @@
CompileTask task = task();
Method method = task.method();
int entryBci = task.osrBci();
+ int compLevel = task.compLevel();
Klass holder = method.getMethodHolder();
out.println("compile " + holder.getName().asString() + " " +
OopUtilities.escapeString(method.getName().asString()) + " " +
method.getSignature().asString() + " " +
- entryBci);
+ entryBci + " " + compLevel);
}
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Wed Jul 05 18:53:57 2017 +0200
@@ -78,6 +78,8 @@
current sweep traversal index. */
private static CIntegerField stackTraversalMarkField;
+ private static CIntegerField compLevelField;
+
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
@@ -113,7 +115,7 @@
osrEntryPointField = type.getAddressField("_osr_entry_point");
lockCountField = type.getJIntField("_lock_count");
stackTraversalMarkField = type.getCIntegerField("_stack_traversal_mark");
-
+ compLevelField = type.getCIntegerField("_comp_level");
pcDescSize = db.lookupType("PcDesc").getSize();
}
@@ -530,7 +532,7 @@
out.println("compile " + holder.getName().asString() + " " +
OopUtilities.escapeString(method.getName().asString()) + " " +
method.getSignature().asString() + " " +
- getEntryBCI());
+ getEntryBCI() + " " + getCompLevel());
}
@@ -551,4 +553,5 @@
private int getHandlerTableOffset() { return (int) handlerTableOffsetField.getValue(addr); }
private int getNulChkTableOffset() { return (int) nulChkTableOffsetField .getValue(addr); }
private int getNMethodEndOffset() { return (int) nmethodEndOffsetField .getValue(addr); }
+ private int getCompLevel() { return (int) compLevelField .getValue(addr); }
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java Wed Jul 05 18:53:57 2017 +0200
@@ -46,10 +46,12 @@
Type type = db.lookupType("CompileTask");
methodField = type.getAddressField("_method");
osrBciField = new CIntField(type.getCIntegerField("_osr_bci"), 0);
+ compLevelField = new CIntField(type.getCIntegerField("_comp_level"), 0);
}
private static AddressField methodField;
private static CIntField osrBciField;
+ private static CIntField compLevelField;
public CompileTask(Address addr) {
super(addr);
@@ -63,4 +65,8 @@
public int osrBci() {
return (int)osrBciField.getValue(getAddress());
}
+
+ public int compLevel() {
+ return (int)compLevelField.getValue(getAddress());
+ }
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java Wed Jul 05 18:53:57 2017 +0200
@@ -117,8 +117,6 @@
mode = MODE_HEAP_SUMMARY;
} else if (modeFlag.equals("-histo")) {
mode = MODE_HISTOGRAM;
- } else if (modeFlag.equals("-permstat")) {
- mode = MODE_CLSTATS;
} else if (modeFlag.equals("-clstats")) {
mode = MODE_CLSTATS;
} else if (modeFlag.equals("-finalizerinfo")) {
--- a/hotspot/make/hotspot_version Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/make/hotspot_version Wed Jul 05 18:53:57 2017 +0200
@@ -35,7 +35,7 @@
HS_MAJOR_VER=25
HS_MINOR_VER=0
-HS_BUILD_NUMBER=30
+HS_BUILD_NUMBER=31
JDK_MAJOR_VER=1
JDK_MINOR_VER=8
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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 "asm/macroAssembler.inline.hpp"
+#include "code/compiledIC.hpp"
+#include "code/icBuffer.hpp"
+#include "code/nmethod.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/safepoint.hpp"
+#ifdef COMPILER2
+#include "opto/matcher.hpp"
+#endif
+
+// Release the CompiledICHolder* associated with this call site is there is one.
+void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) {
+ // This call site might have become stale so inspect it carefully.
+ NativeCall* call = nativeCall_at(call_site->addr());
+ if (is_icholder_entry(call->destination())) {
+ NativeMovConstReg* value = nativeMovConstReg_at(call_site->cached_value());
+ InlineCacheBuffer::queue_for_release((CompiledICHolder*)value->data());
+ }
+}
+
+bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
+ // This call site might have become stale so inspect it carefully.
+ NativeCall* call = nativeCall_at(call_site->addr());
+ return is_icholder_entry(call->destination());
+}
+
+//-----------------------------------------------------------------------------
+// High-level access to an inline cache. Guaranteed to be MT-safe.
+
+CompiledIC::CompiledIC(nmethod* nm, NativeCall* call)
+ : _ic_call(call)
+{
+ address ic_call = call->instruction_address();
+
+ assert(ic_call != NULL, "ic_call address must be set");
+ assert(nm != NULL, "must pass nmethod");
+ assert(nm->contains(ic_call), "must be in nmethod");
+
+ // Search for the ic_call at the given address.
+ RelocIterator iter(nm, ic_call, ic_call+1);
+ bool ret = iter.next();
+ assert(ret == true, "relocInfo must exist at this address");
+ assert(iter.addr() == ic_call, "must find ic_call");
+ if (iter.type() == relocInfo::virtual_call_type) {
+ virtual_call_Relocation* r = iter.virtual_call_reloc();
+ _is_optimized = false;
+ _value = nativeMovConstReg_at(r->cached_value());
+ } else {
+ assert(iter.type() == relocInfo::opt_virtual_call_type, "must be a virtual call");
+ _is_optimized = true;
+ _value = NULL;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+#define __ _masm.
+void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
+#ifdef COMPILER2
+ // Stub is fixed up when the corresponding call is converted from calling
+ // compiled code to calling interpreted code.
+ // set (empty), G5
+ // jmp -1
+
+ address mark = cbuf.insts_mark(); // Get mark within main instrs section.
+
+ MacroAssembler _masm(&cbuf);
+
+ address base =
+ __ start_a_stub(to_interp_stub_size()*2);
+ if (base == NULL) return; // CodeBuffer::expand failed.
+
+ // Static stub relocation stores the instruction address of the call.
+ __ relocate(static_stub_Relocation::spec(mark));
+
+ __ set_metadata(NULL, as_Register(Matcher::inline_cache_reg_encode()));
+
+ __ set_inst_mark();
+ AddressLiteral addrlit(-1);
+ __ JUMP(addrlit, G3, 0);
+
+ __ delayed()->nop();
+
+ // Update current stubs pointer and restore code_end.
+ __ end_a_stub();
+#else
+ ShouldNotReachHere();
+#endif
+}
+#undef __
+
+int CompiledStaticCall::to_interp_stub_size() {
+ // This doesn't need to be accurate but it must be larger or equal to
+ // the real size of the stub.
+ return (NativeMovConstReg::instruction_size + // sethi/setlo;
+ NativeJump::instruction_size + // sethi; jmp; nop
+ (TraceJumps ? 20 * BytesPerInstWord : 0) );
+}
+
+// Relocation entries for call stub, compiled java to interpreter.
+int CompiledStaticCall::reloc_to_interp_stub() {
+ return 10; // 4 in emit_java_to_interp + 1 in Java_Static_Call
+}
+
+void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
+ address stub = find_stub();
+ guarantee(stub != NULL, "stub not found");
+
+ if (TraceICs) {
+ ResourceMark rm;
+ tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
+ instruction_address(),
+ callee->name_and_sig_as_C_string());
+ }
+
+ // Creation also verifies the object.
+ NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+ NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
+
+ assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(),
+ "a) MT-unsafe modification of inline cache");
+ assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry,
+ "b) MT-unsafe modification of inline cache");
+
+ // Update stub.
+ method_holder->set_data((intptr_t)callee());
+ jump->set_jump_destination(entry);
+
+ // Update jump to call.
+ set_destination_mt_safe(stub);
+}
+
+void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+ assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
+ // Reset stub.
+ address stub = static_stub->addr();
+ assert(stub != NULL, "stub not found");
+ // Creation also verifies the object.
+ NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+ NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
+ method_holder->set_data(0);
+ jump->set_jump_destination((address)-1);
+}
+
+//-----------------------------------------------------------------------------
+// Non-product mode code
+#ifndef PRODUCT
+
+void CompiledStaticCall::verify() {
+ // Verify call.
+ NativeCall::verify();
+ if (os::is_MP()) {
+ verify_alignment();
+ }
+
+ // Verify stub.
+ address stub = find_stub();
+ assert(stub != NULL, "no stub found for static call");
+ // Creation also verifies the object.
+ NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+ NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
+
+ // Verify state.
+ assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
+}
+
+#endif // !PRODUCT
--- a/hotspot/src/cpu/sparc/vm/sparc.ad Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Wed Jul 05 18:53:57 2017 +0200
@@ -1656,53 +1656,6 @@
}
//=============================================================================
-
-// emit call stub, compiled java to interpretor
-void emit_java_to_interp(CodeBuffer &cbuf ) {
-
- // Stub is fixed up when the corresponding call is converted from calling
- // compiled code to calling interpreted code.
- // set (empty), G5
- // jmp -1
-
- address mark = cbuf.insts_mark(); // get mark within main instrs section
-
- MacroAssembler _masm(&cbuf);
-
- address base =
- __ start_a_stub(Compile::MAX_stubs_size);
- if (base == NULL) return; // CodeBuffer::expand failed
-
- // static stub relocation stores the instruction address of the call
- __ relocate(static_stub_Relocation::spec(mark));
-
- __ set_metadata(NULL, reg_to_register_object(Matcher::inline_cache_reg_encode()));
-
- __ set_inst_mark();
- AddressLiteral addrlit(-1);
- __ JUMP(addrlit, G3, 0);
-
- __ delayed()->nop();
-
- // Update current stubs pointer and restore code_end.
- __ end_a_stub();
-}
-
-// size of call stub, compiled java to interpretor
-uint size_java_to_interp() {
- // This doesn't need to be accurate but it must be larger or equal to
- // the real size of the stub.
- return (NativeMovConstReg::instruction_size + // sethi/setlo;
- NativeJump::instruction_size + // sethi; jmp; nop
- (TraceJumps ? 20 * BytesPerInstWord : 0) );
-}
-// relocation entries for call stub, compiled java to interpretor
-uint reloc_java_to_interp() {
- return 10; // 4 in emit_java_to_interp + 1 in Java_Static_Call
-}
-
-
-//=============================================================================
#ifndef PRODUCT
void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
st->print_cr("\nUEP:");
@@ -2576,15 +2529,15 @@
enc_class Java_Static_Call (method meth) %{ // JAVA STATIC CALL
// CALL to fixup routine. Fixup routine uses ScopeDesc info to determine
// who we intended to call.
- if ( !_method ) {
+ if (!_method) {
emit_call_reloc(cbuf, $meth$$method, relocInfo::runtime_call_type);
} else if (_optimized_virtual) {
emit_call_reloc(cbuf, $meth$$method, relocInfo::opt_virtual_call_type);
} else {
emit_call_reloc(cbuf, $meth$$method, relocInfo::static_call_type);
}
- if( _method ) { // Emit stub for static call
- emit_java_to_interp(cbuf);
+ if (_method) { // Emit stub for static call.
+ CompiledStaticCall::emit_to_interp_stub(cbuf);
}
%}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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 "asm/macroAssembler.inline.hpp"
+#include "code/compiledIC.hpp"
+#include "code/icBuffer.hpp"
+#include "code/nmethod.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/safepoint.hpp"
+
+// Release the CompiledICHolder* associated with this call site is there is one.
+void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) {
+ // This call site might have become stale so inspect it carefully.
+ NativeCall* call = nativeCall_at(call_site->addr());
+ if (is_icholder_entry(call->destination())) {
+ NativeMovConstReg* value = nativeMovConstReg_at(call_site->cached_value());
+ InlineCacheBuffer::queue_for_release((CompiledICHolder*)value->data());
+ }
+}
+
+bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
+ // This call site might have become stale so inspect it carefully.
+ NativeCall* call = nativeCall_at(call_site->addr());
+ return is_icholder_entry(call->destination());
+}
+
+//-----------------------------------------------------------------------------
+// High-level access to an inline cache. Guaranteed to be MT-safe.
+
+CompiledIC::CompiledIC(nmethod* nm, NativeCall* call)
+ : _ic_call(call)
+{
+ address ic_call = call->instruction_address();
+
+ assert(ic_call != NULL, "ic_call address must be set");
+ assert(nm != NULL, "must pass nmethod");
+ assert(nm->contains(ic_call), "must be in nmethod");
+
+ // Search for the ic_call at the given address.
+ RelocIterator iter(nm, ic_call, ic_call+1);
+ bool ret = iter.next();
+ assert(ret == true, "relocInfo must exist at this address");
+ assert(iter.addr() == ic_call, "must find ic_call");
+ if (iter.type() == relocInfo::virtual_call_type) {
+ virtual_call_Relocation* r = iter.virtual_call_reloc();
+ _is_optimized = false;
+ _value = nativeMovConstReg_at(r->cached_value());
+ } else {
+ assert(iter.type() == relocInfo::opt_virtual_call_type, "must be a virtual call");
+ _is_optimized = true;
+ _value = NULL;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+#define __ _masm.
+void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
+ // Stub is fixed up when the corresponding call is converted from
+ // calling compiled code to calling interpreted code.
+ // movq rbx, 0
+ // jmp -5 # to self
+
+ address mark = cbuf.insts_mark(); // Get mark within main instrs section.
+
+ // Note that the code buffer's insts_mark is always relative to insts.
+ // That's why we must use the macroassembler to generate a stub.
+ MacroAssembler _masm(&cbuf);
+
+ address base =
+ __ start_a_stub(to_interp_stub_size()*2);
+ if (base == NULL) return; // CodeBuffer::expand failed.
+ // Static stub relocation stores the instruction address of the call.
+ __ relocate(static_stub_Relocation::spec(mark), Assembler::imm_operand);
+ // Static stub relocation also tags the Method* in the code-stream.
+ __ mov_metadata(rbx, (Metadata*) NULL); // Method is zapped till fixup time.
+ // This is recognized as unresolved by relocs/nativeinst/ic code.
+ __ jump(RuntimeAddress(__ pc()));
+
+ // Update current stubs pointer and restore insts_end.
+ __ end_a_stub();
+}
+#undef __
+
+int CompiledStaticCall::to_interp_stub_size() {
+ return NOT_LP64(10) // movl; jmp
+ LP64_ONLY(15); // movq (1+1+8); jmp (1+4)
+}
+
+// Relocation entries for call stub, compiled java to interpreter.
+int CompiledStaticCall::reloc_to_interp_stub() {
+ return 4; // 3 in emit_to_interp_stub + 1 in emit_call
+}
+
+void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
+ address stub = find_stub();
+ guarantee(stub != NULL, "stub not found");
+
+ if (TraceICs) {
+ ResourceMark rm;
+ tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
+ instruction_address(),
+ callee->name_and_sig_as_C_string());
+ }
+
+ // Creation also verifies the object.
+ NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+ NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
+
+ assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(),
+ "a) MT-unsafe modification of inline cache");
+ assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry,
+ "b) MT-unsafe modification of inline cache");
+
+ // Update stub.
+ method_holder->set_data((intptr_t)callee());
+ jump->set_jump_destination(entry);
+
+ // Update jump to call.
+ set_destination_mt_safe(stub);
+}
+
+void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+ assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
+ // Reset stub.
+ address stub = static_stub->addr();
+ assert(stub != NULL, "stub not found");
+ // Creation also verifies the object.
+ NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+ NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
+ method_holder->set_data(0);
+ jump->set_jump_destination((address)-1);
+}
+
+//-----------------------------------------------------------------------------
+// Non-product mode code
+#ifndef PRODUCT
+
+void CompiledStaticCall::verify() {
+ // Verify call.
+ NativeCall::verify();
+ if (os::is_MP()) {
+ verify_alignment();
+ }
+
+ // Verify stub.
+ address stub = find_stub();
+ assert(stub != NULL, "no stub found for static call");
+ // Creation also verifies the object.
+ NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+ NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
+
+ // Verify state.
+ assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
+}
+
+#endif // !PRODUCT
--- a/hotspot/src/cpu/x86/vm/x86_32.ad Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/cpu/x86/vm/x86_32.ad Wed Jul 05 18:53:57 2017 +0200
@@ -1257,43 +1257,6 @@
}
//=============================================================================
-
-// emit call stub, compiled java to interpreter
-void emit_java_to_interp(CodeBuffer &cbuf ) {
- // Stub is fixed up when the corresponding call is converted from calling
- // compiled code to calling interpreted code.
- // mov rbx,0
- // jmp -1
-
- address mark = cbuf.insts_mark(); // get mark within main instrs section
-
- // Note that the code buffer's insts_mark is always relative to insts.
- // That's why we must use the macroassembler to generate a stub.
- MacroAssembler _masm(&cbuf);
-
- address base =
- __ start_a_stub(Compile::MAX_stubs_size);
- if (base == NULL) return; // CodeBuffer::expand failed
- // static stub relocation stores the instruction address of the call
- __ relocate(static_stub_Relocation::spec(mark), RELOC_IMM32);
- // static stub relocation also tags the Method* in the code-stream.
- __ mov_metadata(rbx, (Metadata*)NULL); // method is zapped till fixup time
- // This is recognized as unresolved by relocs/nativeInst/ic code
- __ jump(RuntimeAddress(__ pc()));
-
- __ end_a_stub();
- // Update current stubs pointer and restore insts_end.
-}
-// size of call stub, compiled java to interpretor
-uint size_java_to_interp() {
- return 10; // movl; jmp
-}
-// relocation entries for call stub, compiled java to interpretor
-uint reloc_java_to_interp() {
- return 4; // 3 in emit_java_to_interp + 1 in Java_Static_Call
-}
-
-//=============================================================================
#ifndef PRODUCT
void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream* st ) const {
st->print_cr( "CMP EAX,[ECX+4]\t# Inline cache check");
@@ -1909,8 +1872,8 @@
emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4),
static_call_Relocation::spec(), RELOC_IMM32 );
}
- if (_method) { // Emit stub for static call
- emit_java_to_interp(cbuf);
+ if (_method) { // Emit stub for static call.
+ CompiledStaticCall::emit_to_interp_stub(cbuf);
}
%}
--- a/hotspot/src/cpu/x86/vm/x86_64.ad Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad Wed Jul 05 18:53:57 2017 +0200
@@ -1388,48 +1388,6 @@
}
//=============================================================================
-
-// emit call stub, compiled java to interpreter
-void emit_java_to_interp(CodeBuffer& cbuf)
-{
- // Stub is fixed up when the corresponding call is converted from
- // calling compiled code to calling interpreted code.
- // movq rbx, 0
- // jmp -5 # to self
-
- address mark = cbuf.insts_mark(); // get mark within main instrs section
-
- // Note that the code buffer's insts_mark is always relative to insts.
- // That's why we must use the macroassembler to generate a stub.
- MacroAssembler _masm(&cbuf);
-
- address base =
- __ start_a_stub(Compile::MAX_stubs_size);
- if (base == NULL) return; // CodeBuffer::expand failed
- // static stub relocation stores the instruction address of the call
- __ relocate(static_stub_Relocation::spec(mark), RELOC_IMM64);
- // static stub relocation also tags the Method* in the code-stream.
- __ mov_metadata(rbx, (Metadata*) NULL); // method is zapped till fixup time
- // This is recognized as unresolved by relocs/nativeinst/ic code
- __ jump(RuntimeAddress(__ pc()));
-
- // Update current stubs pointer and restore insts_end.
- __ end_a_stub();
-}
-
-// size of call stub, compiled java to interpretor
-uint size_java_to_interp()
-{
- return 15; // movq (1+1+8); jmp (1+4)
-}
-
-// relocation entries for call stub, compiled java to interpretor
-uint reloc_java_to_interp()
-{
- return 4; // 3 in emit_java_to_interp + 1 in Java_Static_Call
-}
-
-//=============================================================================
#ifndef PRODUCT
void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const
{
@@ -2078,8 +2036,8 @@
RELOC_DISP32);
}
if (_method) {
- // Emit stub for static call
- emit_java_to_interp(cbuf);
+ // Emit stub for static call.
+ CompiledStaticCall::emit_to_interp_stub(cbuf);
}
%}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/zero/vm/compiledIC_zero.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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 "classfile/systemDictionary.hpp"
+#include "code/codeCache.hpp"
+#include "code/compiledIC.hpp"
+#include "code/icBuffer.hpp"
+#include "code/nmethod.hpp"
+#include "code/vtableStubs.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/linkResolver.hpp"
+#include "memory/metadataFactory.hpp"
+#include "memory/oopFactory.hpp"
+#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/symbol.hpp"
+#include "runtime/icache.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "utilities/events.hpp"
+
+
+// Release the CompiledICHolder* associated with this call site is there is one.
+void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) {
+ // This call site might have become stale so inspect it carefully.
+ NativeCall* call = nativeCall_at(call_site->addr());
+ if (is_icholder_entry(call->destination())) {
+ NativeMovConstReg* value = nativeMovConstReg_at(call_site->cached_value());
+ InlineCacheBuffer::queue_for_release((CompiledICHolder*)value->data());
+ }
+}
+
+bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
+ // This call site might have become stale so inspect it carefully.
+ NativeCall* call = nativeCall_at(call_site->addr());
+ return is_icholder_entry(call->destination());
+}
+
+//-----------------------------------------------------------------------------
+// High-level access to an inline cache. Guaranteed to be MT-safe.
+
+CompiledIC::CompiledIC(nmethod* nm, NativeCall* call)
+ : _ic_call(call)
+{
+ address ic_call = call->instruction_address();
+
+ assert(ic_call != NULL, "ic_call address must be set");
+ assert(nm != NULL, "must pass nmethod");
+ assert(nm->contains(ic_call), "must be in nmethod");
+
+ // Search for the ic_call at the given address.
+ RelocIterator iter(nm, ic_call, ic_call+1);
+ bool ret = iter.next();
+ assert(ret == true, "relocInfo must exist at this address");
+ assert(iter.addr() == ic_call, "must find ic_call");
+ if (iter.type() == relocInfo::virtual_call_type) {
+ virtual_call_Relocation* r = iter.virtual_call_reloc();
+ _is_optimized = false;
+ _value = nativeMovConstReg_at(r->cached_value());
+ } else {
+ assert(iter.type() == relocInfo::opt_virtual_call_type, "must be a virtual call");
+ _is_optimized = true;
+ _value = NULL;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
+ ShouldNotReachHere(); // Only needed for COMPILER2.
+}
+
+int CompiledStaticCall::to_interp_stub_size() {
+ ShouldNotReachHere(); // Only needed for COMPILER2.
+ return 0;
+}
+
+// Relocation entries for call stub, compiled java to interpreter.
+int CompiledStaticCall::reloc_to_interp_stub() {
+ ShouldNotReachHere(); // Only needed for COMPILER2.
+ return 0;
+}
+
+void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
+ ShouldNotReachHere(); // Only needed for COMPILER2.
+}
+
+void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+ ShouldNotReachHere(); // Only needed for COMPILER2.
+}
+
+//-----------------------------------------------------------------------------
+// Non-product mode code.
+#ifndef PRODUCT
+
+void CompiledStaticCall::verify() {
+ ShouldNotReachHere(); // Only needed for COMPILER2.
+}
+
+#endif // !PRODUCT
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -1230,10 +1230,6 @@
return retval;
}
-const char* os::get_current_directory(char *buf, int buflen) {
- return getcwd(buf, buflen);
-}
-
// check if addr is inside libjvm.so
bool os::address_is_in_vm(address addr) {
static address libjvm_base_addr;
@@ -2080,9 +2076,10 @@
flags |= MAP_FIXED;
}
- // Map uncommitted pages PROT_READ and PROT_WRITE, change access
- // to PROT_EXEC if executable when we commit the page.
- addr = (char*)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE,
+ // Map reserved/uncommitted pages PROT_NONE so we fail early if we
+ // touch an uncommitted page. Otherwise, the read/write might
+ // succeed if we have enough swap space to back the physical page.
+ addr = (char*)::mmap(requested_addr, bytes, PROT_NONE,
flags, -1, 0);
if (addr != MAP_FAILED) {
--- a/hotspot/src/os/linux/vm/os_linux.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -119,6 +119,7 @@
Mutex* os::Linux::_createThread_lock = NULL;
pthread_t os::Linux::_main_thread;
int os::Linux::_page_size = -1;
+const int os::Linux::_vm_default_page_size = (8 * K);
bool os::Linux::_is_floating_stack = false;
bool os::Linux::_is_NPTL = false;
bool os::Linux::_supports_fast_thread_cpu_time = false;
@@ -1662,10 +1663,6 @@
return retval;
}
-const char* os::get_current_directory(char *buf, int buflen) {
- return getcwd(buf, buflen);
-}
-
// check if addr is inside libjvm.so
bool os::address_is_in_vm(address addr) {
static address libjvm_base_addr;
@@ -2906,9 +2903,10 @@
flags |= MAP_FIXED;
}
- // Map uncommitted pages PROT_READ and PROT_WRITE, change access
- // to PROT_EXEC if executable when we commit the page.
- addr = (char*)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE,
+ // Map reserved/uncommitted pages PROT_NONE so we fail early if we
+ // touch an uncommitted page. Otherwise, the read/write might
+ // succeed if we have enough swap space to back the physical page.
+ addr = (char*)::mmap(requested_addr, bytes, PROT_NONE,
flags, -1, 0);
if (addr != MAP_FAILED) {
@@ -4249,6 +4247,15 @@
Linux::clock_init();
initial_time_count = os::elapsed_counter();
pthread_mutex_init(&dl_mutex, NULL);
+
+ // If the pagesize of the VM is greater than 8K determine the appropriate
+ // number of initial guard pages. The user can change this with the
+ // command line arguments, if needed.
+ if (vm_page_size() > (int)Linux::vm_default_page_size()) {
+ StackYellowPages = 1;
+ StackRedPages = 1;
+ StackShadowPages = round_to((StackShadowPages*Linux::vm_default_page_size()), vm_page_size()) / vm_page_size();
+ }
}
// To install functions for atexit system call
@@ -4302,8 +4309,8 @@
// Add in 2*BytesPerWord times page size to account for VM stack during
// class initialization depending on 32 or 64 bit VM.
os::Linux::min_stack_allowed = MAX2(os::Linux::min_stack_allowed,
- (size_t)(StackYellowPages+StackRedPages+StackShadowPages+
- 2*BytesPerWord COMPILER2_PRESENT(+1)) * Linux::page_size());
+ (size_t)(StackYellowPages+StackRedPages+StackShadowPages) * Linux::page_size() +
+ (2*BytesPerWord COMPILER2_PRESENT(+1)) * Linux::vm_default_page_size());
size_t threadStackSizeInBytes = ThreadStackSize * K;
if (threadStackSizeInBytes != 0 &&
--- a/hotspot/src/os/linux/vm/os_linux.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/os/linux/vm/os_linux.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -70,6 +70,7 @@
static pthread_t _main_thread;
static Mutex* _createThread_lock;
static int _page_size;
+ static const int _vm_default_page_size;
static julong available_memory();
static julong physical_memory() { return _physical_memory; }
@@ -116,6 +117,8 @@
static int page_size(void) { return _page_size; }
static void set_page_size(int val) { _page_size = val; }
+ static int vm_default_page_size(void) { return _vm_default_page_size; }
+
static address ucontext_get_pc(ucontext_t* uc);
static intptr_t* ucontext_get_sp(ucontext_t* uc);
static intptr_t* ucontext_get_fp(ucontext_t* uc);
--- a/hotspot/src/os/posix/vm/os_posix.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/os/posix/vm/os_posix.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -251,3 +251,11 @@
return true;
#endif
}
+
+const char* os::get_current_directory(char *buf, size_t buflen) {
+ return getcwd(buf, buflen);
+}
+
+FILE* os::open(int fd, const char* mode) {
+ return ::fdopen(fd, mode);
+}
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -824,7 +824,7 @@
// allocate new buffer and initialize
info = (Dl_serinfo*)malloc(_info.dls_size);
if (info == NULL) {
- vm_exit_out_of_memory(_info.dls_size,
+ vm_exit_out_of_memory(_info.dls_size, OOM_MALLOC_ERROR,
"init_system_properties_values info");
}
info->dls_size = _info.dls_size;
@@ -866,7 +866,7 @@
common_path = malloc(bufsize);
if (common_path == NULL) {
free(info);
- vm_exit_out_of_memory(bufsize,
+ vm_exit_out_of_memory(bufsize, OOM_MALLOC_ERROR,
"init_system_properties_values common_path");
}
sprintf(common_path, COMMON_DIR "/lib/%s", cpu_arch);
@@ -879,7 +879,7 @@
if (library_path == NULL) {
free(info);
free(common_path);
- vm_exit_out_of_memory(bufsize,
+ vm_exit_out_of_memory(bufsize, OOM_MALLOC_ERROR,
"init_system_properties_values library_path");
}
library_path[0] = '\0';
@@ -1623,7 +1623,8 @@
// %%% this is used only in threadLocalStorage.cpp
if (thr_setspecific((thread_key_t)index, value)) {
if (errno == ENOMEM) {
- vm_exit_out_of_memory(SMALLINT, "thr_setspecific: out of swap space");
+ vm_exit_out_of_memory(SMALLINT, OOM_MALLOC_ERROR,
+ "thr_setspecific: out of swap space");
} else {
fatal(err_msg("os::thread_local_storage_at_put: thr_setspecific failed "
"(%s)", strerror(errno)));
@@ -1915,10 +1916,6 @@
return retval;
}
-const char* os::get_current_directory(char *buf, int buflen) {
- return getcwd(buf, buflen);
-}
-
// check if addr is inside libjvm.so
bool os::address_is_in_vm(address addr) {
static address libjvm_base_addr;
--- a/hotspot/src/os/windows/vm/os_windows.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -1221,8 +1221,10 @@
// Needs to be in os specific directory because windows requires another
// header file <direct.h>
-const char* os::get_current_directory(char *buf, int buflen) {
- return _getcwd(buf, buflen);
+const char* os::get_current_directory(char *buf, size_t buflen) {
+ int n = static_cast<int>(buflen);
+ if (buflen > INT_MAX) n = INT_MAX;
+ return _getcwd(buf, n);
}
//-----------------------------------------------------------
@@ -4098,6 +4100,10 @@
return ::open(pathbuf, oflag | O_BINARY | O_NOINHERIT, mode);
}
+FILE* os::open(int fd, const char* mode) {
+ return ::_fdopen(fd, mode);
+}
+
// Is a (classpath) directory empty?
bool os::dir_is_empty(const char* path) {
WIN32_FIND_DATA fd;
--- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -178,7 +178,7 @@
// JVM needs to know exact stack location, abort if it fails
if (rslt != 0) {
if (rslt == ENOMEM) {
- vm_exit_out_of_memory(0, "pthread_getattr_np");
+ vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np");
} else {
fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt));
}
--- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -710,7 +710,7 @@
// JVM needs to know exact stack location, abort if it fails
if (rslt != 0) {
if (rslt == ENOMEM) {
- vm_exit_out_of_memory(0, "pthread_getattr_np");
+ vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np");
} else {
fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt));
}
--- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -313,7 +313,7 @@
int res = pthread_getattr_np(pthread_self(), &attr);
if (res != 0) {
if (res == ENOMEM) {
- vm_exit_out_of_memory(0, "pthread_getattr_np");
+ vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np");
}
else {
fatal(err_msg("pthread_getattr_np failed with errno = %d", res));
--- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -591,7 +591,7 @@
// on the thread stack, which could get a mapping error when touched.
address addr = (address) info->si_addr;
if (sig == SIGBUS && info->si_code == BUS_OBJERR && info->si_errno == ENOMEM) {
- vm_exit_out_of_memory(0, "Out of swap space to map in thread stack.");
+ vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "Out of swap space to map in thread stack.");
}
VMError err(t, sig, pc, info, ucVoid);
--- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -745,7 +745,7 @@
// on the thread stack, which could get a mapping error when touched.
address addr = (address) info->si_addr;
if (sig == SIGBUS && info->si_code == BUS_OBJERR && info->si_errno == ENOMEM) {
- vm_exit_out_of_memory(0, "Out of swap space to map in thread stack.");
+ vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "Out of swap space to map in thread stack.");
}
VMError err(t, sig, pc, info, ucVoid);
--- a/hotspot/src/share/vm/adlc/main.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/adlc/main.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -213,6 +213,7 @@
AD.addInclude(AD._CPP_file, "adfiles", get_basename(AD._HPP_file._name));
AD.addInclude(AD._CPP_file, "memory/allocation.inline.hpp");
AD.addInclude(AD._CPP_file, "asm/macroAssembler.inline.hpp");
+ AD.addInclude(AD._CPP_file, "code/compiledIC.hpp");
AD.addInclude(AD._CPP_file, "code/vmreg.hpp");
AD.addInclude(AD._CPP_file, "gc_interface/collectedHeap.inline.hpp");
AD.addInclude(AD._CPP_file, "oops/compiledICHolder.hpp");
--- a/hotspot/src/share/vm/asm/assembler.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/asm/assembler.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -44,7 +44,7 @@
CodeSection* cs = code->insts();
cs->clear_mark(); // new assembler kills old mark
if (cs->start() == NULL) {
- vm_exit_out_of_memory(0, err_msg("CodeCache: no room for %s",
+ vm_exit_out_of_memory(0, OOM_MMAP_ERROR, err_msg("CodeCache: no room for %s",
code->name()));
}
_code_section = cs;
--- a/hotspot/src/share/vm/ci/ciEnv.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciEnv.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -483,7 +483,8 @@
{
// We have to lock the cpool to keep the oop from being resolved
// while we are accessing it.
- MonitorLockerEx ml(cpool->lock());
+ oop cplock = cpool->lock();
+ ObjectLocker ol(cplock, THREAD, cplock != NULL);
constantTag tag = cpool->tag_at(index);
if (tag.is_klass()) {
// The klass has been inserted into the constant pool
@@ -1149,23 +1150,9 @@
record_method_not_compilable("out of memory");
}
-fileStream* ciEnv::_replay_data_stream = NULL;
-
-void ciEnv::dump_replay_data() {
+void ciEnv::dump_replay_data(outputStream* out) {
VM_ENTRY_MARK;
MutexLocker ml(Compile_lock);
- if (_replay_data_stream == NULL) {
- _replay_data_stream = new (ResourceObj::C_HEAP, mtCompiler) fileStream(ReplayDataFile);
- if (_replay_data_stream == NULL) {
- fatal(err_msg("Can't open %s for replay data", ReplayDataFile));
- }
- }
- dump_replay_data(_replay_data_stream);
-}
-
-
-void ciEnv::dump_replay_data(outputStream* out) {
- ASSERT_IN_VM;
ResourceMark rm;
#if INCLUDE_JVMTI
out->print_cr("JvmtiExport can_access_local_variables %d", _jvmti_can_access_local_variables);
@@ -1178,13 +1165,15 @@
for (int i = 0; i < objects->length(); i++) {
objects->at(i)->dump_replay_data(out);
}
- Method* method = task()->method();
- int entry_bci = task()->osr_bci();
+ CompileTask* task = this->task();
+ Method* method = task->method();
+ int entry_bci = task->osr_bci();
+ int comp_level = task->comp_level();
// Klass holder = method->method_holder();
- out->print_cr("compile %s %s %s %d",
+ out->print_cr("compile %s %s %s %d %d",
method->klass_name()->as_quoted_ascii(),
method->name()->as_quoted_ascii(),
method->signature()->as_quoted_ascii(),
- entry_bci);
+ entry_bci, comp_level);
out->flush();
}
--- a/hotspot/src/share/vm/ci/ciEnv.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciEnv.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -46,8 +46,6 @@
friend class CompileBroker;
friend class Dependencies; // for get_object, during logging
- static fileStream* _replay_data_stream;
-
private:
Arena* _arena; // Alias for _ciEnv_arena except in init_shared_objects()
Arena _ciEnv_arena;
@@ -451,10 +449,6 @@
// RedefineClasses support
void metadata_do(void f(Metadata*)) { _factory->metadata_do(f); }
- // Dump the compilation replay data for this ciEnv to
- // ReplayDataFile, creating the file if needed.
- void dump_replay_data();
-
// Dump the compilation replay data for the ciEnv to the stream.
void dump_replay_data(outputStream* out);
};
--- a/hotspot/src/share/vm/ci/ciMethod.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciMethod.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -196,7 +196,6 @@
// Analysis and profiling.
//
// Usage note: liveness_at_bci and init_vars should be wrapped in ResourceMarks.
- bool uses_monitors() const { return _uses_monitors; } // this one should go away, it has a misleading name
bool has_monitor_bytecodes() const { return _uses_monitors; }
bool has_balanced_monitors();
--- a/hotspot/src/share/vm/ci/ciReplay.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciReplay.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -89,7 +89,7 @@
loader = Handle(thread, SystemDictionary::java_system_loader());
stream = fopen(filename, "rt");
if (stream == NULL) {
- fprintf(stderr, "Can't open replay file %s\n", filename);
+ fprintf(stderr, "ERROR: Can't open replay file %s\n", filename);
}
buffer_length = 32;
buffer = NEW_RESOURCE_ARRAY(char, buffer_length);
@@ -327,7 +327,6 @@
if (had_error()) {
tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message);
tty->print_cr("%s", buffer);
- assert(false, "error");
return;
}
pos = 0;
@@ -370,11 +369,47 @@
}
}
- // compile <klass> <name> <signature> <entry_bci>
+ // validation of comp_level
+ bool is_valid_comp_level(int comp_level) {
+ const int msg_len = 256;
+ char* msg = NULL;
+ if (!is_compile(comp_level)) {
+ msg = NEW_RESOURCE_ARRAY(char, msg_len);
+ jio_snprintf(msg, msg_len, "%d isn't compilation level", comp_level);
+ } else if (!TieredCompilation && (comp_level != CompLevel_highest_tier)) {
+ msg = NEW_RESOURCE_ARRAY(char, msg_len);
+ switch (comp_level) {
+ case CompLevel_simple:
+ jio_snprintf(msg, msg_len, "compilation level %d requires Client VM or TieredCompilation", comp_level);
+ break;
+ case CompLevel_full_optimization:
+ jio_snprintf(msg, msg_len, "compilation level %d requires Server VM", comp_level);
+ break;
+ default:
+ jio_snprintf(msg, msg_len, "compilation level %d requires TieredCompilation", comp_level);
+ }
+ }
+ if (msg != NULL) {
+ report_error(msg);
+ return false;
+ }
+ return true;
+ }
+
+ // compile <klass> <name> <signature> <entry_bci> <comp_level>
void process_compile(TRAPS) {
// methodHandle method;
Method* method = parse_method(CHECK);
int entry_bci = parse_int("entry_bci");
+ const char* comp_level_label = "comp_level";
+ int comp_level = parse_int(comp_level_label);
+ // old version w/o comp_level
+ if (had_error() && (error_message() == comp_level_label)) {
+ comp_level = CompLevel_full_optimization;
+ }
+ if (!is_valid_comp_level(comp_level)) {
+ return;
+ }
Klass* k = method->method_holder();
((InstanceKlass*)k)->initialize(THREAD);
if (HAS_PENDING_EXCEPTION) {
@@ -389,12 +424,12 @@
}
}
// Make sure the existence of a prior compile doesn't stop this one
- nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, CompLevel_full_optimization, true) : method->code();
+ nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code();
if (nm != NULL) {
nm->make_not_entrant();
}
replay_state = this;
- CompileBroker::compile_method(method, entry_bci, CompLevel_full_optimization,
+ CompileBroker::compile_method(method, entry_bci, comp_level,
methodHandle(), 0, "replay", THREAD);
replay_state = NULL;
reset();
@@ -551,7 +586,7 @@
if (parsed_two_word == i) continue;
default:
- ShouldNotReachHere();
+ fatal(err_msg_res("Unexpected tag: %d", cp->tag_at(i).value()));
break;
}
@@ -819,6 +854,11 @@
ReplaySuppressInitializers = 1;
}
+ if (FLAG_IS_DEFAULT(ReplayDataFile)) {
+ tty->print_cr("ERROR: no compiler replay data file specified (use -XX:ReplayDataFile=replay_pid12345.txt).");
+ return 1;
+ }
+
// Load and parse the replay data
CompileReplay rp(ReplayDataFile, THREAD);
int exit_code = 0;
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -2027,7 +2027,6 @@
u2 method_parameters_length = 0;
u1* method_parameters_data = NULL;
bool method_parameters_seen = false;
- bool method_parameters_four_byte_flags;
bool parsed_code_attribute = false;
bool parsed_checked_exceptions_attribute = false;
bool parsed_stackmap_attribute = false;
@@ -2241,26 +2240,14 @@
}
method_parameters_seen = true;
method_parameters_length = cfs->get_u1_fast();
- // Track the actual size (note: this is written for clarity; a
- // decent compiler will CSE and constant-fold this into a single
- // expression)
- // Use the attribute length to figure out the size of flags
- if (method_attribute_length == (method_parameters_length * 6u) + 1u) {
- method_parameters_four_byte_flags = true;
- } else if (method_attribute_length == (method_parameters_length * 4u) + 1u) {
- method_parameters_four_byte_flags = false;
- } else {
+ if (method_attribute_length != (method_parameters_length * 4u) + 1u) {
classfile_parse_error(
"Invalid MethodParameters method attribute length %u in class file",
method_attribute_length, CHECK_(nullHandle));
}
method_parameters_data = cfs->get_u1_buffer();
cfs->skip_u2_fast(method_parameters_length);
- if (method_parameters_four_byte_flags) {
- cfs->skip_u4_fast(method_parameters_length);
- } else {
- cfs->skip_u2_fast(method_parameters_length);
- }
+ cfs->skip_u2_fast(method_parameters_length);
// ignore this attribute if it cannot be reflected
if (!SystemDictionary::Parameter_klass_loaded())
method_parameters_length = 0;
@@ -2423,13 +2410,8 @@
for (int i = 0; i < method_parameters_length; i++) {
elem[i].name_cp_index = Bytes::get_Java_u2(method_parameters_data);
method_parameters_data += 2;
- if (method_parameters_four_byte_flags) {
- elem[i].flags = Bytes::get_Java_u4(method_parameters_data);
- method_parameters_data += 4;
- } else {
- elem[i].flags = Bytes::get_Java_u2(method_parameters_data);
- method_parameters_data += 2;
- }
+ elem[i].flags = Bytes::get_Java_u2(method_parameters_data);
+ method_parameters_data += 2;
}
}
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -304,7 +304,19 @@
inline void assert_property(bool b, const char* msg, TRAPS) {
#ifdef ASSERT
- if (!b) { fatal(msg); }
+ if (!b) {
+ ResourceMark rm(THREAD);
+ fatal(err_msg(msg, _class_name->as_C_string()));
+ }
+#endif
+ }
+
+ inline void assert_property(bool b, const char* msg, int index, TRAPS) {
+#ifdef ASSERT
+ if (!b) {
+ ResourceMark rm(THREAD);
+ fatal(err_msg(msg, index, _class_name->as_C_string()));
+ }
#endif
}
@@ -312,7 +324,7 @@
if (_need_verify) {
guarantee_property(property, msg, index, CHECK);
} else {
- assert_property(property, msg, CHECK);
+ assert_property(property, msg, index, CHECK);
}
}
--- a/hotspot/src/share/vm/classfile/classLoader.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -1345,9 +1345,10 @@
tty->print_cr("CompileTheWorld (%d) : %s", _compile_the_world_class_counter, buffer);
// Preload all classes to get around uncommon traps
// Iterate over all methods in class
+ int comp_level = CompilationPolicy::policy()->initial_compile_level();
for (int n = 0; n < k->methods()->length(); n++) {
methodHandle m (THREAD, k->methods()->at(n));
- if (CompilationPolicy::can_be_compiled(m)) {
+ if (CompilationPolicy::can_be_compiled(m, comp_level)) {
if (++_codecache_sweep_counter == CompileTheWorldSafepointInterval) {
// Give sweeper a chance to keep up with CTW
@@ -1356,7 +1357,7 @@
_codecache_sweep_counter = 0;
}
// Force compilation
- CompileBroker::compile_method(m, InvocationEntryBci, CompilationPolicy::policy()->initial_compile_level(),
+ CompileBroker::compile_method(m, InvocationEntryBci, comp_level,
methodHandle(), 0, "CTW", THREAD);
if (HAS_PENDING_EXCEPTION) {
clear_pending_exception_if_not_oom(CHECK);
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -53,6 +53,7 @@
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
+#include "memory/gcLocker.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/oopFactory.hpp"
@@ -65,17 +66,19 @@
ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
-ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) :
+ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) :
_class_loader(h_class_loader()),
_is_anonymous(is_anonymous), _keep_alive(is_anonymous), // initially
_metaspace(NULL), _unloading(false), _klasses(NULL),
_claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL),
- _next(NULL), _dependencies(),
+ _next(NULL), _dependencies(dependencies),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) {
// empty
}
void ClassLoaderData::init_dependencies(TRAPS) {
+ assert(!Universe::is_fully_initialized(), "should only be called when initializing");
+ assert(is_the_null_class_loader_data(), "should only call this for the null class loader");
_dependencies.init(CHECK);
}
@@ -277,6 +280,9 @@
void ClassLoaderData::unload() {
_unloading = true;
+ // Tell serviceability tools these classes are unloading
+ classes_do(InstanceKlass::notify_unload_class);
+
if (TraceClassLoaderData) {
ResourceMark rm;
tty->print("[ClassLoaderData: unload loader data "PTR_FORMAT, this);
@@ -300,6 +306,9 @@
ClassLoaderData::~ClassLoaderData() {
+ // Release C heap structures for all the classes.
+ classes_do(InstanceKlass::release_C_heap_structures);
+
Metaspace *m = _metaspace;
if (m != NULL) {
_metaspace = NULL;
@@ -423,7 +432,7 @@
// These anonymous class loaders are to contain classes used for JSR292
ClassLoaderData* ClassLoaderData::anonymous_class_loader_data(oop loader, TRAPS) {
// Add a new class loader data to the graph.
- return ClassLoaderDataGraph::add(NULL, loader, CHECK_NULL);
+ return ClassLoaderDataGraph::add(loader, true, CHECK_NULL);
}
const char* ClassLoaderData::loader_name() {
@@ -495,19 +504,22 @@
ClassLoaderData* ClassLoaderDataGraph::_unloading = NULL;
ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL;
-
// Add a new class loader data node to the list. Assign the newly created
// ClassLoaderData into the java/lang/ClassLoader object as a hidden field
-ClassLoaderData* ClassLoaderDataGraph::add(ClassLoaderData** cld_addr, Handle loader, TRAPS) {
- // Not assigned a class loader data yet.
- // Create one.
- ClassLoaderData* *list_head = &_head;
- ClassLoaderData* next = _head;
+ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous, TRAPS) {
+ // We need to allocate all the oops for the ClassLoaderData before allocating the
+ // actual ClassLoaderData object.
+ ClassLoaderData::Dependencies dependencies(CHECK_NULL);
- bool is_anonymous = (cld_addr == NULL);
- ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous);
+ No_Safepoint_Verifier no_safepoints; // we mustn't GC until we've installed the
+ // ClassLoaderData in the graph since the CLD
+ // contains unhandled oops
- if (cld_addr != NULL) {
+ ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous, dependencies);
+
+
+ if (!is_anonymous) {
+ ClassLoaderData** cld_addr = java_lang_ClassLoader::loader_data_addr(loader());
// First, Atomically set it
ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL);
if (old != NULL) {
@@ -519,6 +531,9 @@
// We won the race, and therefore the task of adding the data to the list of
// class loader data
+ ClassLoaderData** list_head = &_head;
+ ClassLoaderData* next = _head;
+
do {
cld->set_next(next);
ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next);
@@ -531,10 +546,6 @@
cld->loader_name());
tty->print_cr("]");
}
- // Create dependencies after the CLD is added to the list. Otherwise,
- // the GC GC will not find the CLD and the _class_loader field will
- // not be updated.
- cld->init_dependencies(CHECK_NULL);
return cld;
}
next = exchanged;
@@ -665,6 +676,8 @@
dead->unload();
data = data->next();
// Remove from loader list.
+ // This class loader data will no longer be found
+ // in the ClassLoaderDataGraph.
if (prev != NULL) {
prev->set_next(data);
} else {
@@ -686,6 +699,7 @@
next = purge_me->next();
delete purge_me;
}
+ Metaspace::purge();
}
// CDS support
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -62,7 +62,7 @@
// CMS support.
static ClassLoaderData* _saved_head;
- static ClassLoaderData* add(ClassLoaderData** loader_data_addr, Handle class_loader, TRAPS);
+ static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS);
public:
static ClassLoaderData* find_or_create(Handle class_loader, TRAPS);
static void purge();
@@ -100,6 +100,9 @@
Thread* THREAD);
public:
Dependencies() : _list_head(NULL) {}
+ Dependencies(TRAPS) : _list_head(NULL) {
+ init(CHECK);
+ }
void add(Handle dependency, TRAPS);
void init(TRAPS);
void oops_do(OopClosure* f);
@@ -150,7 +153,7 @@
void set_next(ClassLoaderData* next) { _next = next; }
ClassLoaderData* next() const { return _next; }
- ClassLoaderData(Handle h_class_loader, bool is_anonymous);
+ ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies);
~ClassLoaderData();
void set_metaspace(Metaspace* m) { _metaspace = m; }
@@ -190,7 +193,9 @@
static void init_null_class_loader_data() {
assert(_the_null_class_loader_data == NULL, "cannot initialize twice");
assert(ClassLoaderDataGraph::_head == NULL, "cannot initialize twice");
- _the_null_class_loader_data = new ClassLoaderData((oop)NULL, false);
+
+ // We explicitly initialize the Dependencies object at a later phase in the initialization
+ _the_null_class_loader_data = new ClassLoaderData((oop)NULL, false, Dependencies());
ClassLoaderDataGraph::_head = _the_null_class_loader_data;
assert(_the_null_class_loader_data->is_the_null_class_loader_data(), "Must be");
if (DumpSharedSpaces) {
--- a/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -43,10 +43,9 @@
assert(loader() != NULL,"Must be a class loader");
// Gets the class loader data out of the java/lang/ClassLoader object, if non-null
// it's already in the loader_data, so no need to add
- ClassLoaderData** loader_data_addr = java_lang_ClassLoader::loader_data_addr(loader());
- ClassLoaderData* loader_data_id = *loader_data_addr;
- if (loader_data_id) {
- return loader_data_id;
+ ClassLoaderData* loader_data= java_lang_ClassLoader::loader_data(loader());
+ if (loader_data) {
+ return loader_data;
}
- return ClassLoaderDataGraph::add(loader_data_addr, loader, THREAD);
+ return ClassLoaderDataGraph::add(loader, false, THREAD);
}
--- a/hotspot/src/share/vm/classfile/dictionary.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/classfile/dictionary.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -27,7 +27,6 @@
#include "classfile/systemDictionary.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiRedefineClassesTrace.hpp"
-#include "services/classLoadingService.hpp"
#include "utilities/hashtable.inline.hpp"
@@ -156,19 +155,7 @@
if (k_def_class_loader_data == loader_data) {
// This is the defining entry, so the referred class is about
// to be unloaded.
- // Notify the debugger and clean up the class.
class_was_unloaded = true;
- // notify the debugger
- if (JvmtiExport::should_post_class_unload()) {
- JvmtiExport::post_class_unload(ik);
- }
-
- // notify ClassLoadingService of class unload
- ClassLoadingService::notify_class_unloaded(ik);
-
- // Clean up C heap
- ik->release_C_heap_structures();
- ik->constants()->release_C_heap_structures();
}
// Also remove this system dictionary entry.
purge_entry = true;
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -315,14 +315,18 @@
return string;
}
-jchar* java_lang_String::as_unicode_string(oop java_string, int& length) {
+jchar* java_lang_String::as_unicode_string(oop java_string, int& length, TRAPS) {
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
length = java_lang_String::length(java_string);
- jchar* result = NEW_RESOURCE_ARRAY(jchar, length);
- for (int index = 0; index < length; index++) {
- result[index] = value->char_at(index + offset);
+ jchar* result = NEW_RESOURCE_ARRAY_RETURN_NULL(jchar, length);
+ if (result != NULL) {
+ for (int index = 0; index < length; index++) {
+ result[index] = value->char_at(index + offset);
+ }
+ } else {
+ THROW_MSG_0(vmSymbols::java_lang_OutOfMemoryError(), "could not allocate Unicode string");
}
return result;
}
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -153,7 +153,7 @@
static char* as_utf8_string(oop java_string, char* buf, int buflen);
static char* as_utf8_string(oop java_string, int start, int len);
static char* as_platform_dependent_str(Handle java_string, TRAPS);
- static jchar* as_unicode_string(oop java_string, int& length);
+ static jchar* as_unicode_string(oop java_string, int& length, TRAPS);
// produce an ascii string with all other values quoted using \u####
static char* as_quoted_ascii(oop java_string);
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -735,7 +735,7 @@
ResourceMark rm(THREAD);
int length;
Handle h_string (THREAD, string);
- jchar* chars = java_lang_String::as_unicode_string(string, length);
+ jchar* chars = java_lang_String::as_unicode_string(string, length, CHECK_NULL);
oop result = intern(h_string, chars, length, CHECK_NULL);
return result;
}
--- a/hotspot/src/share/vm/code/codeCache.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/code/codeCache.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -463,8 +463,10 @@
}
#endif //PRODUCT
-
-nmethod* CodeCache::find_and_remove_saved_code(Method* m) {
+/**
+ * Remove and return nmethod from the saved code list in order to reanimate it.
+ */
+nmethod* CodeCache::reanimate_saved_code(Method* m) {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
nmethod* saved = _saved_nmethods;
nmethod* prev = NULL;
@@ -479,7 +481,7 @@
saved->set_speculatively_disconnected(false);
saved->set_saved_nmethod_link(NULL);
if (PrintMethodFlushing) {
- saved->print_on(tty, " ### nmethod is reconnected\n");
+ saved->print_on(tty, " ### nmethod is reconnected");
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
@@ -496,6 +498,9 @@
return NULL;
}
+/**
+ * Remove nmethod from the saved code list in order to discard it permanently
+ */
void CodeCache::remove_saved_code(nmethod* nm) {
// For conc swpr this will be called with CodeCache_lock taken by caller
assert_locked_or_safepoint(CodeCache_lock);
@@ -529,7 +534,7 @@
nm->set_saved_nmethod_link(_saved_nmethods);
_saved_nmethods = nm;
if (PrintMethodFlushing) {
- nm->print_on(tty, " ### nmethod is speculatively disconnected\n");
+ nm->print_on(tty, " ### nmethod is speculatively disconnected");
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
--- a/hotspot/src/share/vm/code/codeCache.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/code/codeCache.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -57,7 +57,7 @@
static int _number_of_nmethods_with_dependencies;
static bool _needs_cache_clean;
static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link()
- static nmethod* _saved_nmethods; // linked via nm->saved_nmethod_look()
+ static nmethod* _saved_nmethods; // Linked list of speculatively disconnected nmethods.
static void verify_if_often() PRODUCT_RETURN;
@@ -168,7 +168,7 @@
static void set_needs_cache_clean(bool v) { _needs_cache_clean = v; }
static void clear_inline_caches(); // clear all inline caches
- static nmethod* find_and_remove_saved_code(Method* m);
+ static nmethod* reanimate_saved_code(Method* m);
static void remove_saved_code(nmethod* nm);
static void speculatively_disconnect(nmethod* nm);
--- a/hotspot/src/share/vm/code/compiledIC.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/code/compiledIC.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -45,25 +45,6 @@
// Every time a compiled IC is changed or its type is being accessed,
// either the CompiledIC_lock must be set or we must be at a safe point.
-
-// Release the CompiledICHolder* associated with this call site is there is one.
-void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) {
- // This call site might have become stale so inspect it carefully.
- NativeCall* call = nativeCall_at(call_site->addr());
- if (is_icholder_entry(call->destination())) {
- NativeMovConstReg* value = nativeMovConstReg_at(call_site->cached_value());
- InlineCacheBuffer::queue_for_release((CompiledICHolder*)value->data());
- }
-}
-
-
-bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
- // This call site might have become stale so inspect it carefully.
- NativeCall* call = nativeCall_at(call_site->addr());
- return is_icholder_entry(call->destination());
-}
-
-
//-----------------------------------------------------------------------------
// Low-level access to an inline cache. Private, since they might not be
// MT-safe to use.
@@ -488,33 +469,6 @@
return (cb != NULL && cb->is_adapter_blob());
}
-
-CompiledIC::CompiledIC(nmethod* nm, NativeCall* call)
- : _ic_call(call)
-{
- address ic_call = call->instruction_address();
-
- assert(ic_call != NULL, "ic_call address must be set");
- assert(nm != NULL, "must pass nmethod");
- assert(nm->contains(ic_call), "must be in nmethod");
-
- // search for the ic_call at the given address
- RelocIterator iter(nm, ic_call, ic_call+1);
- bool ret = iter.next();
- assert(ret == true, "relocInfo must exist at this address");
- assert(iter.addr() == ic_call, "must find ic_call");
- if (iter.type() == relocInfo::virtual_call_type) {
- virtual_call_Relocation* r = iter.virtual_call_reloc();
- _is_optimized = false;
- _value = nativeMovConstReg_at(r->cached_value());
- } else {
- assert(iter.type() == relocInfo::opt_virtual_call_type, "must be a virtual call");
- _is_optimized = true;
- _value = NULL;
-}
-}
-
-
// ----------------------------------------------------------------------------
void CompiledStaticCall::set_to_clean() {
@@ -549,33 +503,6 @@
return nm->stub_contains(destination());
}
-
-void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
- address stub=find_stub();
- guarantee(stub != NULL, "stub not found");
-
- if (TraceICs) {
- ResourceMark rm;
- tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
- instruction_address(),
- callee->name_and_sig_as_C_string());
- }
-
- NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); // creation also verifies the object
- NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
-
- assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(), "a) MT-unsafe modification of inline cache");
- assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry, "b) MT-unsafe modification of inline cache");
-
- // Update stub
- method_holder->set_data((intptr_t)callee());
- jump->set_jump_destination(entry);
-
- // Update jump to call
- set_destination_mt_safe(stub);
-}
-
-
void CompiledStaticCall::set(const StaticCallInfo& info) {
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag);
@@ -618,19 +545,6 @@
}
}
-
-void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
- assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
- // Reset stub
- address stub = static_stub->addr();
- assert(stub!=NULL, "stub not found");
- NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); // creation also verifies the object
- NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
- method_holder->set_data(0);
- jump->set_jump_destination((address)-1);
-}
-
-
address CompiledStaticCall::find_stub() {
// Find reloc. information containing this call-site
RelocIterator iter((nmethod*)NULL, instruction_address());
@@ -668,19 +582,16 @@
|| is_optimized() || is_megamorphic(), "sanity check");
}
-
void CompiledIC::print() {
print_compiled_ic();
tty->cr();
}
-
void CompiledIC::print_compiled_ic() {
tty->print("Inline cache at " INTPTR_FORMAT ", calling %s " INTPTR_FORMAT " cached_value " INTPTR_FORMAT,
instruction_address(), is_call_to_interpreted() ? "interpreted " : "", ic_destination(), is_optimized() ? NULL : cached_value());
}
-
void CompiledStaticCall::print() {
tty->print("static call at " INTPTR_FORMAT " -> ", instruction_address());
if (is_clean()) {
@@ -693,21 +604,4 @@
tty->cr();
}
-void CompiledStaticCall::verify() {
- // Verify call
- NativeCall::verify();
- if (os::is_MP()) {
- verify_alignment();
- }
-
- // Verify stub
- address stub = find_stub();
- assert(stub != NULL, "no stub found for static call");
- NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); // creation also verifies the object
- NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
-
- // Verify state
- assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
-}
-
-#endif
+#endif // !PRODUCT
--- a/hotspot/src/share/vm/code/compiledIC.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/code/compiledIC.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -304,6 +304,11 @@
friend CompiledStaticCall* compiledStaticCall_at(address native_call);
friend CompiledStaticCall* compiledStaticCall_at(Relocation* call_site);
+ // Code
+ static void emit_to_interp_stub(CodeBuffer &cbuf);
+ static int to_interp_stub_size();
+ static int reloc_to_interp_stub();
+
// State
bool is_clean() const;
bool is_call_to_compiled() const;
--- a/hotspot/src/share/vm/code/stubs.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/code/stubs.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -67,7 +67,7 @@
intptr_t size = round_to(buffer_size, 2*BytesPerWord);
BufferBlob* blob = BufferBlob::create(name, size);
if( blob == NULL) {
- vm_exit_out_of_memory(size, err_msg("CodeCache: no room for %s", name));
+ vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, err_msg("CodeCache: no room for %s", name));
}
_stub_interface = stub_interface;
_buffer_size = blob->content_size();
--- a/hotspot/src/share/vm/code/vtableStubs.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/code/vtableStubs.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -60,7 +60,7 @@
const int bytes = chunk_factor * real_size + pd_code_alignment();
BufferBlob* blob = BufferBlob::create("vtable chunks", bytes);
if (blob == NULL) {
- vm_exit_out_of_memory(bytes, "CodeCache: no room for vtable chunks");
+ vm_exit_out_of_memory(bytes, OOM_MALLOC_ERROR, "CodeCache: no room for vtable chunks");
}
_chunk = blob->content_begin();
_chunk_end = _chunk + bytes;
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -65,7 +65,7 @@
HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end,
char*, intptr_t, char*, intptr_t, char*, intptr_t, char*, intptr_t, bool);
-#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name) \
+#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, comp_name) \
{ \
Symbol* klass_name = (method)->klass_name(); \
Symbol* name = (method)->name(); \
@@ -77,8 +77,7 @@
signature->bytes(), signature->utf8_length()); \
}
-#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, \
- comp_name, success) \
+#define DTRACE_METHOD_COMPILE_END_PROBE(method, comp_name, success) \
{ \
Symbol* klass_name = (method)->klass_name(); \
Symbol* name = (method)->name(); \
@@ -92,7 +91,7 @@
#else /* USDT2 */
-#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name) \
+#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, comp_name) \
{ \
Symbol* klass_name = (method)->klass_name(); \
Symbol* name = (method)->name(); \
@@ -104,8 +103,7 @@
(char *) signature->bytes(), signature->utf8_length()); \
}
-#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, \
- comp_name, success) \
+#define DTRACE_METHOD_COMPILE_END_PROBE(method, comp_name, success) \
{ \
Symbol* klass_name = (method)->klass_name(); \
Symbol* name = (method)->name(); \
@@ -120,8 +118,8 @@
#else // ndef DTRACE_ENABLED
-#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name)
-#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, comp_name, success)
+#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, comp_name)
+#define DTRACE_METHOD_COMPILE_END_PROBE(method, comp_name, success)
#endif // ndef DTRACE_ENABLED
@@ -1229,7 +1227,7 @@
if (method->is_not_compilable(comp_level)) return NULL;
if (UseCodeCacheFlushing) {
- nmethod* saved = CodeCache::find_and_remove_saved_code(method());
+ nmethod* saved = CodeCache::reanimate_saved_code(method());
if (saved != NULL) {
method->set_code(method, saved);
return saved;
@@ -1288,9 +1286,9 @@
method->jmethod_id();
}
- // If the compiler is shut off due to code cache flushing or otherwise,
+ // If the compiler is shut off due to code cache getting full
// fail out now so blocking compiles dont hang the java thread
- if (!should_compile_new_jobs() || (UseCodeCacheFlushing && CodeCache::needs_flushing())) {
+ if (!should_compile_new_jobs()) {
CompilationPolicy::policy()->delay_compilation(method());
return NULL;
}
@@ -1766,8 +1764,7 @@
// Save information about this method in case of failure.
set_last_compile(thread, method, is_osr, task_level);
- DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler(task_level), method,
- compiler_name(task_level));
+ DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, compiler_name(task_level));
}
// Allocate a new set of JNI handles.
@@ -1842,13 +1839,14 @@
}
}
}
+ // simulate crash during compilation
+ assert(task->compile_id() != CICrashAt, "just as planned");
}
pop_jni_handle_block();
methodHandle method(thread, task->method());
- DTRACE_METHOD_COMPILE_END_PROBE(compiler(task_level), method,
- compiler_name(task_level), task->is_success());
+ DTRACE_METHOD_COMPILE_END_PROBE(method, compiler_name(task_level), task->is_success());
collect_statistics(thread, time, task);
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -2444,8 +2444,7 @@
// initial marking in checkpointRootsInitialWork has been completed
if (VerifyDuringGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
- gclog_or_tty->print("Verify before initial mark: ");
- Universe::verify();
+ Universe::verify("Verify before initial mark: ");
}
{
bool res = markFromRoots(false);
@@ -2456,8 +2455,7 @@
case FinalMarking:
if (VerifyDuringGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
- gclog_or_tty->print("Verify before re-mark: ");
- Universe::verify();
+ Universe::verify("Verify before re-mark: ");
}
checkpointRootsFinal(false, clear_all_soft_refs,
init_mark_was_synchronous);
@@ -2468,8 +2466,7 @@
// final marking in checkpointRootsFinal has been completed
if (VerifyDuringGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
- gclog_or_tty->print("Verify before sweep: ");
- Universe::verify();
+ Universe::verify("Verify before sweep: ");
}
sweep(false);
assert(_collectorState == Resizing, "Incorrect state");
@@ -2484,8 +2481,7 @@
// The heap has been resized.
if (VerifyDuringGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
- gclog_or_tty->print("Verify before reset: ");
- Universe::verify();
+ Universe::verify("Verify before reset: ");
}
reset(false);
assert(_collectorState == Idling, "Collector state should "
@@ -2853,8 +2849,8 @@
bool failed() { return _failed; }
};
-bool CMSCollector::verify_after_remark() {
- gclog_or_tty->print(" [Verifying CMS Marking... ");
+bool CMSCollector::verify_after_remark(bool silent) {
+ if (!silent) gclog_or_tty->print(" [Verifying CMS Marking... ");
MutexLockerEx ml(verification_mark_bm()->lock(), Mutex::_no_safepoint_check_flag);
static bool init = false;
@@ -2915,7 +2911,7 @@
warning("Unrecognized value %d for CMSRemarkVerifyVariant",
CMSRemarkVerifyVariant);
}
- gclog_or_tty->print(" done] ");
+ if (!silent) gclog_or_tty->print(" done] ");
return true;
}
@@ -3426,8 +3422,9 @@
void ConcurrentMarkSweepGeneration::shrink_free_list_by(size_t bytes) {
assert_locked_or_safepoint(Heap_lock);
assert_lock_strong(freelistLock());
- // XXX Fix when compaction is implemented.
- warning("Shrinking of CMS not yet implemented");
+ if (PrintGCDetails && Verbose) {
+ warning("Shrinking of CMS not yet implemented");
+ }
return;
}
@@ -6010,26 +6007,23 @@
&cmsDrainMarkingStackClosure,
NULL);
}
- verify_work_stacks_empty();
- }
+ }
+
+ // This is the point where the entire marking should have completed.
+ verify_work_stacks_empty();
if (should_unload_classes()) {
{
TraceTime t("class unloading", PrintGCDetails, false, gclog_or_tty);
- // Follow SystemDictionary roots and unload classes
+ // Unload classes and purge the SystemDictionary.
bool purged_class = SystemDictionary::do_unloading(&_is_alive_closure);
- // Follow CodeCache roots and unload any methods marked for unloading
+ // Unload nmethods.
CodeCache::do_unloading(&_is_alive_closure, purged_class);
- cmsDrainMarkingStackClosure.do_void();
- verify_work_stacks_empty();
-
- // Update subklass/sibling/implementor links in KlassKlass descendants
+ // Prune dead klasses from subklass/sibling/implementor lists.
Klass::clean_weak_klass_links(&_is_alive_closure);
- // Nothing should have been pushed onto the working stacks.
- verify_work_stacks_empty();
}
{
@@ -6043,11 +6037,10 @@
// Need to check if we really scanned the StringTable.
if ((roots_scanning_options() & SharedHeap::SO_Strings) == 0) {
TraceTime t("scrub string table", PrintGCDetails, false, gclog_or_tty);
- // Now clean up stale oops in StringTable
+ // Delete entries for dead interned strings.
StringTable::unlink(&_is_alive_closure);
}
- verify_work_stacks_empty();
// Restore any preserved marks as a result of mark stack or
// work queue overflow
restore_preserved_marks_if_any(); // done single-threaded for now
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -990,7 +990,7 @@
// debugging
void verify();
- bool verify_after_remark();
+ bool verify_after_remark(bool silent = VerifySilently);
void verify_ok_to_terminate() const PRODUCT_RETURN;
void verify_work_stacks_empty() const PRODUCT_RETURN;
void verify_overflow_empty() const PRODUCT_RETURN;
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -1273,10 +1273,9 @@
if (VerifyDuringGC) {
HandleMark hm; // handle scope
- gclog_or_tty->print(" VerifyDuringGC:(before)");
Universe::heap()->prepare_for_verify();
- Universe::verify(/* silent */ false,
- /* option */ VerifyOption_G1UsePrevMarking);
+ Universe::verify(VerifyOption_G1UsePrevMarking,
+ " VerifyDuringGC:(before)");
}
G1CollectorPolicy* g1p = g1h->g1_policy();
@@ -1300,10 +1299,9 @@
// Verify the heap w.r.t. the previous marking bitmap.
if (VerifyDuringGC) {
HandleMark hm; // handle scope
- gclog_or_tty->print(" VerifyDuringGC:(overflow)");
Universe::heap()->prepare_for_verify();
- Universe::verify(/* silent */ false,
- /* option */ VerifyOption_G1UsePrevMarking);
+ Universe::verify(VerifyOption_G1UsePrevMarking,
+ " VerifyDuringGC:(overflow)");
}
// Clear the marking state because we will be restarting
@@ -1323,10 +1321,9 @@
if (VerifyDuringGC) {
HandleMark hm; // handle scope
- gclog_or_tty->print(" VerifyDuringGC:(after)");
Universe::heap()->prepare_for_verify();
- Universe::verify(/* silent */ false,
- /* option */ VerifyOption_G1UseNextMarking);
+ Universe::verify(VerifyOption_G1UseNextMarking,
+ " VerifyDuringGC:(after)");
}
assert(!restart_for_overflow(), "sanity");
// Completely reset the marking state since marking completed
@@ -1972,10 +1969,9 @@
if (VerifyDuringGC) {
HandleMark hm; // handle scope
- gclog_or_tty->print(" VerifyDuringGC:(before)");
Universe::heap()->prepare_for_verify();
- Universe::verify(/* silent */ false,
- /* option */ VerifyOption_G1UsePrevMarking);
+ Universe::verify(VerifyOption_G1UsePrevMarking,
+ " VerifyDuringGC:(before)");
}
G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy();
@@ -2127,10 +2123,9 @@
if (VerifyDuringGC) {
HandleMark hm; // handle scope
- gclog_or_tty->print(" VerifyDuringGC:(after)");
Universe::heap()->prepare_for_verify();
- Universe::verify(/* silent */ false,
- /* option */ VerifyOption_G1UsePrevMarking);
+ Universe::verify(VerifyOption_G1UsePrevMarking,
+ " VerifyDuringGC:(after)");
}
g1h->verify_region_sets_optional();
--- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -77,7 +77,7 @@
assert(delta > 0, "just checking");
if (!_vs.expand_by(delta)) {
// Do better than this for Merlin
- vm_exit_out_of_memory(delta, "offset table expansion");
+ vm_exit_out_of_memory(delta, OOM_MMAP_ERROR, "offset table expansion");
}
assert(_vs.high() == high + delta, "invalid expansion");
// Initialization of the contents is left to the
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -1271,9 +1271,8 @@
if (guard && total_collections() >= VerifyGCStartAt) {
double verify_start = os::elapsedTime();
HandleMark hm; // Discard invalid handles created during verification
- gclog_or_tty->print(msg);
prepare_for_verify();
- Universe::verify(false /* silent */, VerifyOption_G1UsePrevMarking);
+ Universe::verify(VerifyOption_G1UsePrevMarking, msg);
verify_time_ms = (os::elapsedTime() - verify_start) * 1000;
}
@@ -1304,7 +1303,7 @@
print_heap_before_gc();
- size_t metadata_prev_used = MetaspaceAux::used_in_bytes();
+ size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes();
HRSPhaseSetter x(HRSPhaseFullGC);
verify_region_sets_optional();
@@ -1425,6 +1424,7 @@
// Delete metaspaces for unloaded class loaders and clean up loader_data graph
ClassLoaderDataGraph::purge();
+ MetaspaceAux::verify_metrics();
// Note: since we've just done a full GC, concurrent
// marking is no longer active. Therefore we need not
@@ -1831,7 +1831,7 @@
if (G1ExitOnExpansionFailure &&
_g1_storage.uncommitted_size() >= aligned_expand_bytes) {
// We had head room...
- vm_exit_out_of_memory(aligned_expand_bytes, "G1 heap expansion");
+ vm_exit_out_of_memory(aligned_expand_bytes, OOM_MMAP_ERROR, "G1 heap expansion");
}
}
return successful;
@@ -1955,13 +1955,6 @@
int n_rem_sets = HeapRegionRemSet::num_par_rem_sets();
assert(n_rem_sets > 0, "Invariant.");
- HeapRegionRemSetIterator** iter_arr =
- NEW_C_HEAP_ARRAY(HeapRegionRemSetIterator*, n_queues, mtGC);
- for (int i = 0; i < n_queues; i++) {
- iter_arr[i] = new HeapRegionRemSetIterator();
- }
- _rem_set_iterator = iter_arr;
-
_worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues, mtGC);
_worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(unsigned int, n_queues, mtGC);
@@ -3614,7 +3607,7 @@
uint array_length = g1_policy()->young_cset_region_length();
_surviving_young_words = NEW_C_HEAP_ARRAY(size_t, (size_t) array_length, mtGC);
if (_surviving_young_words == NULL) {
- vm_exit_out_of_memory(sizeof(size_t) * array_length,
+ vm_exit_out_of_memory(sizeof(size_t) * array_length, OOM_MALLOC_ERROR,
"Not enough space for young surv words summary.");
}
memset(_surviving_young_words, 0, (size_t) array_length * sizeof(size_t));
@@ -4397,7 +4390,7 @@
PADDING_ELEM_NUM;
_surviving_young_words_base = NEW_C_HEAP_ARRAY(size_t, array_length, mtGC);
if (_surviving_young_words_base == NULL)
- vm_exit_out_of_memory(array_length * sizeof(size_t),
+ vm_exit_out_of_memory(array_length * sizeof(size_t), OOM_MALLOC_ERROR,
"Not enough space for young surv histo.");
_surviving_young_words = _surviving_young_words_base + PADDING_ELEM_NUM;
memset(_surviving_young_words, 0, (size_t) real_length * sizeof(size_t));
@@ -5079,10 +5072,9 @@
}
void
-G1CollectedHeap::g1_process_weak_roots(OopClosure* root_closure,
- OopClosure* non_root_closure) {
+G1CollectedHeap::g1_process_weak_roots(OopClosure* root_closure) {
CodeBlobToOopClosure roots_in_blobs(root_closure, /*do_marking=*/ false);
- SharedHeap::process_weak_roots(root_closure, &roots_in_blobs, non_root_closure);
+ SharedHeap::process_weak_roots(root_closure, &roots_in_blobs);
}
// Weak Reference Processing support
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -786,9 +786,6 @@
// concurrently after the collection.
DirtyCardQueueSet _dirty_card_queue_set;
- // The Heap Region Rem Set Iterator.
- HeapRegionRemSetIterator** _rem_set_iterator;
-
// The closure used to refine a single card.
RefineCardTableEntryClosure* _refine_cte_cl;
@@ -827,8 +824,7 @@
// Apply "blk" to all the weak roots of the system. These include
// JNI weak roots, the code cache, system dictionary, symbol table,
// string table, and referents of reachable weak refs.
- void g1_process_weak_roots(OopClosure* root_closure,
- OopClosure* non_root_closure);
+ void g1_process_weak_roots(OopClosure* root_closure);
// Frees a non-humongous region by initializing its contents and
// adding it to the free list that's passed as a parameter (this is
@@ -1114,15 +1110,6 @@
G1RemSet* g1_rem_set() const { return _g1_rem_set; }
ModRefBarrierSet* mr_bs() const { return _mr_bs; }
- // The rem set iterator.
- HeapRegionRemSetIterator* rem_set_iterator(int i) {
- return _rem_set_iterator[i];
- }
-
- HeapRegionRemSetIterator* rem_set_iterator() {
- return _rem_set_iterator[0];
- }
-
unsigned get_gc_time_stamp() {
return _gc_time_stamp;
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -144,33 +144,28 @@
&GenMarkSweep::follow_stack_closure,
NULL);
- // Follow system dictionary roots and unload classes
+
+ // This is the point where the entire marking should have completed.
+ assert(GenMarkSweep::_marking_stack.is_empty(), "Marking should have completed");
+
+ // Unload classes and purge the SystemDictionary.
bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive);
- assert(GenMarkSweep::_marking_stack.is_empty(),
- "stack should be empty by now");
- // Follow code cache roots (has to be done after system dictionary,
- // assumes all live klasses are marked)
+ // Unload nmethods.
CodeCache::do_unloading(&GenMarkSweep::is_alive, purged_class);
- GenMarkSweep::follow_stack();
- // Update subklass/sibling/implementor links of live klasses
+ // Prune dead klasses from subklass/sibling/implementor lists.
Klass::clean_weak_klass_links(&GenMarkSweep::is_alive);
- assert(GenMarkSweep::_marking_stack.is_empty(),
- "stack should be empty by now");
- // Visit interned string tables and delete unmarked oops
+ // Delete entries for dead interned strings.
StringTable::unlink(&GenMarkSweep::is_alive);
+
// Clean up unreferenced symbols in symbol table.
SymbolTable::unlink();
- assert(GenMarkSweep::_marking_stack.is_empty(),
- "stack should be empty by now");
-
if (VerifyDuringGC) {
HandleMark hm; // handle scope
COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact);
- gclog_or_tty->print(" VerifyDuringGC:(full)[Verifying ");
Universe::heap()->prepare_for_verify();
// Note: we can verify only the heap here. When an object is
// marked, the previous value of the mark word (including
@@ -182,11 +177,13 @@
// fail. At the end of the GC, the orginal mark word values
// (including hash values) are restored to the appropriate
// objects.
- Universe::heap()->verify(/* silent */ false,
- /* option */ VerifyOption_G1UseMarkWord);
-
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
- gclog_or_tty->print_cr("]");
+ if (!VerifySilently) {
+ gclog_or_tty->print(" VerifyDuringGC:(full)[Verifying ");
+ }
+ Universe::heap()->verify(VerifySilently, VerifyOption_G1UseMarkWord);
+ if (!VerifySilently) {
+ gclog_or_tty->print_cr("]");
+ }
}
}
@@ -308,17 +305,16 @@
sh->process_strong_roots(true, // activate StrongRootsScope
false, // not scavenging.
SharedHeap::SO_AllClasses,
- &GenMarkSweep::adjust_root_pointer_closure,
+ &GenMarkSweep::adjust_pointer_closure,
NULL, // do not touch code cache here
&GenMarkSweep::adjust_klass_closure);
assert(GenMarkSweep::ref_processor() == g1h->ref_processor_stw(), "Sanity");
- g1h->ref_processor_stw()->weak_oops_do(&GenMarkSweep::adjust_root_pointer_closure);
+ g1h->ref_processor_stw()->weak_oops_do(&GenMarkSweep::adjust_pointer_closure);
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
- g1h->g1_process_weak_roots(&GenMarkSweep::adjust_root_pointer_closure,
- &GenMarkSweep::adjust_pointer_closure);
+ g1h->g1_process_weak_roots(&GenMarkSweep::adjust_pointer_closure);
GenMarkSweep::adjust_marks();
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -169,14 +169,13 @@
// _try_claimed || r->claim_iter()
// is true: either we're supposed to work on claimed-but-not-complete
// regions, or we successfully claimed the region.
- HeapRegionRemSetIterator* iter = _g1h->rem_set_iterator(_worker_i);
- hrrs->init_iterator(iter);
+ HeapRegionRemSetIterator iter(hrrs);
size_t card_index;
// We claim cards in block so as to recude the contention. The block size is determined by
// the G1RSetScanBlockSize parameter.
size_t jump_to_card = hrrs->iter_claimed_next(_block_size);
- for (size_t current_card = 0; iter->has_next(card_index); current_card++) {
+ for (size_t current_card = 0; iter.has_next(card_index); current_card++) {
if (current_card >= jump_to_card + _block_size) {
jump_to_card = hrrs->iter_claimed_next(_block_size);
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -53,14 +53,14 @@
NumSeqTasks = 1
};
- CardTableModRefBS* _ct_bs;
- SubTasksDone* _seq_task;
- G1CollectorPolicy* _g1p;
+ CardTableModRefBS* _ct_bs;
+ SubTasksDone* _seq_task;
+ G1CollectorPolicy* _g1p;
- ConcurrentG1Refine* _cg1r;
+ ConcurrentG1Refine* _cg1r;
- size_t* _cards_scanned;
- size_t _total_cards_scanned;
+ size_t* _cards_scanned;
+ size_t _total_cards_scanned;
// Used for caching the closure that is responsible for scanning
// references into the collection set.
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -285,7 +285,7 @@
_fine_grain_regions = new PerRegionTablePtr[_max_fine_entries];
if (_fine_grain_regions == NULL) {
- vm_exit_out_of_memory(sizeof(void*)*_max_fine_entries,
+ vm_exit_out_of_memory(sizeof(void*)*_max_fine_entries, OOM_MALLOC_ERROR,
"Failed to allocate _fine_grain_entries.");
}
@@ -877,14 +877,9 @@
return _iter_state == Complete;
}
-void HeapRegionRemSet::init_iterator(HeapRegionRemSetIterator* iter) const {
- iter->initialize(this);
-}
-
#ifndef PRODUCT
void HeapRegionRemSet::print() const {
- HeapRegionRemSetIterator iter;
- init_iterator(&iter);
+ HeapRegionRemSetIterator iter(this);
size_t card_index;
while (iter.has_next(card_index)) {
HeapWord* card_start =
@@ -928,35 +923,23 @@
//-------------------- Iteration --------------------
-HeapRegionRemSetIterator::
-HeapRegionRemSetIterator() :
- _hrrs(NULL),
+HeapRegionRemSetIterator:: HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs) :
+ _hrrs(hrrs),
_g1h(G1CollectedHeap::heap()),
- _bosa(NULL),
- _sparse_iter() { }
-
-void HeapRegionRemSetIterator::initialize(const HeapRegionRemSet* hrrs) {
- _hrrs = hrrs;
- _coarse_map = &_hrrs->_other_regions._coarse_map;
- _fine_grain_regions = _hrrs->_other_regions._fine_grain_regions;
- _bosa = _hrrs->bosa();
-
- _is = Sparse;
+ _coarse_map(&hrrs->_other_regions._coarse_map),
+ _fine_grain_regions(hrrs->_other_regions._fine_grain_regions),
+ _bosa(hrrs->bosa()),
+ _is(Sparse),
// Set these values so that we increment to the first region.
- _coarse_cur_region_index = -1;
- _coarse_cur_region_cur_card = (HeapRegion::CardsPerRegion-1);
-
- _cur_region_cur_card = 0;
-
- _fine_array_index = -1;
- _fine_cur_prt = NULL;
-
- _n_yielded_coarse = 0;
- _n_yielded_fine = 0;
- _n_yielded_sparse = 0;
-
- _sparse_iter.init(&hrrs->_other_regions._sparse_table);
-}
+ _coarse_cur_region_index(-1),
+ _coarse_cur_region_cur_card(HeapRegion::CardsPerRegion-1),
+ _cur_region_cur_card(0),
+ _fine_array_index(-1),
+ _fine_cur_prt(NULL),
+ _n_yielded_coarse(0),
+ _n_yielded_fine(0),
+ _n_yielded_sparse(0),
+ _sparse_iter(&hrrs->_other_regions._sparse_table) {}
bool HeapRegionRemSetIterator::coarse_has_next(size_t& card_index) {
if (_hrrs->_other_regions._n_coarse_entries == 0) return false;
@@ -1209,8 +1192,7 @@
hrrs->add_reference((OopOrNarrowOopStar)hr5->bottom());
// Now, does iteration yield these three?
- HeapRegionRemSetIterator iter;
- hrrs->init_iterator(&iter);
+ HeapRegionRemSetIterator iter(hrrs);
size_t sum = 0;
size_t card_index;
while (iter.has_next(card_index)) {
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -281,9 +281,6 @@
return (_iter_state == Unclaimed) && (_iter_claimed == 0);
}
- // Initialize the given iterator to iterate over this rem set.
- void init_iterator(HeapRegionRemSetIterator* iter) const;
-
// The actual # of bytes this hr_remset takes up.
size_t mem_size() {
return _other_regions.mem_size()
@@ -345,9 +342,9 @@
#endif
};
-class HeapRegionRemSetIterator : public CHeapObj<mtGC> {
+class HeapRegionRemSetIterator : public StackObj {
- // The region over which we're iterating.
+ // The region RSet over which we're iterating.
const HeapRegionRemSet* _hrrs;
// Local caching of HRRS fields.
@@ -362,8 +359,10 @@
size_t _n_yielded_coarse;
size_t _n_yielded_sparse;
- // If true we're iterating over the coarse table; if false the fine
- // table.
+ // Indicates what granularity of table that we're currently iterating over.
+ // We start iterating over the sparse table, progress to the fine grain
+ // table, and then finish with the coarse table.
+ // See HeapRegionRemSetIterator::has_next().
enum IterState {
Sparse,
Fine,
@@ -403,9 +402,7 @@
public:
// We require an iterator to be initialized before use, so the
// constructor does little.
- HeapRegionRemSetIterator();
-
- void initialize(const HeapRegionRemSet* hrrs);
+ HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs);
// If there remains one or more cards to be yielded, returns true and
// sets "card_index" to one of those cards (which is then considered
--- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -35,10 +35,6 @@
#define UNROLL_CARD_LOOPS 1
-void SparsePRT::init_iterator(SparsePRTIter* sprt_iter) {
- sprt_iter->init(this);
-}
-
void SparsePRTEntry::init(RegionIdx_t region_ind) {
_region_ind = region_ind;
_next_index = NullEntry;
--- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -192,18 +192,11 @@
size_t compute_card_ind(CardIdx_t ci);
public:
- RSHashTableIter() :
- _tbl_ind(RSHashTable::NullEntry),
+ RSHashTableIter(RSHashTable* rsht) :
+ _tbl_ind(RSHashTable::NullEntry), // So that first increment gets to 0.
_bl_ind(RSHashTable::NullEntry),
_card_ind((SparsePRTEntry::cards_num() - 1)),
- _rsht(NULL) {}
-
- void init(RSHashTable* rsht) {
- _rsht = rsht;
- _tbl_ind = -1; // So that first increment gets to 0.
- _bl_ind = RSHashTable::NullEntry;
- _card_ind = (SparsePRTEntry::cards_num() - 1);
- }
+ _rsht(rsht) {}
bool has_next(size_t& card_index);
};
@@ -284,8 +277,6 @@
static void cleanup_all();
RSHashTable* cur() const { return _cur; }
- void init_iterator(SparsePRTIter* sprt_iter);
-
static void add_to_expanded_list(SparsePRT* sprt);
static SparsePRT* get_from_expanded_list();
@@ -321,9 +312,9 @@
class SparsePRTIter: public RSHashTableIter {
public:
- void init(const SparsePRT* sprt) {
- RSHashTableIter::init(sprt->cur());
- }
+ SparsePRTIter(const SparsePRT* sprt) :
+ RSHashTableIter(sprt->cur()) {}
+
bool has_next(size_t& card_index) {
return RSHashTableIter::has_next(card_index);
}
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -567,7 +567,7 @@
MemRegion(new_start_aligned, new_end_for_commit);
if (!os::commit_memory((char*)new_committed.start(),
new_committed.byte_size())) {
- vm_exit_out_of_memory(new_committed.byte_size(),
+ vm_exit_out_of_memory(new_committed.byte_size(), OOM_MMAP_ERROR,
"card table expansion");
}
}
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/gcTaskThread.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/gcTaskThread.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -43,7 +43,7 @@
_time_stamp_index(0)
{
if (!os::create_thread(this, os::pgc_thread))
- vm_exit_out_of_memory(0, "Cannot create GC thread. Out of system resources.");
+ vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GC thread. Out of system resources.");
if (PrintGCTaskTimeStamps) {
_time_stamps = NEW_C_HEAP_ARRAY(GCTaskTimeStamp, GCTaskTimeStampEntries, mtGC);
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/objectStartArray.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/objectStartArray.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -99,7 +99,7 @@
// Expand
size_t expand_by = requested_blocks_size_in_bytes - current_blocks_size_in_bytes;
if (!_virtual_space.expand_by(expand_by)) {
- vm_exit_out_of_memory(expand_by, "object start array expansion");
+ vm_exit_out_of_memory(expand_by, OOM_MMAP_ERROR, "object start array expansion");
}
// Clear *only* the newly allocated region
memset(_blocks_region.end(), clean_block, expand_by);
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -138,8 +138,7 @@
if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
- gclog_or_tty->print(" VerifyBeforeGC:");
- Universe::verify();
+ Universe::verify(" VerifyBeforeGC:");
}
// Verify object start arrays
@@ -177,7 +176,7 @@
size_t prev_used = heap->used();
// Capture metadata size before collection for sizing.
- size_t metadata_prev_used = MetaspaceAux::used_in_bytes();
+ size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes();
// For PrintGCDetails
size_t old_gen_prev_used = old_gen->used_in_bytes();
@@ -238,6 +237,7 @@
// Delete metaspaces for unloaded class loaders and clean up loader_data graph
ClassLoaderDataGraph::purge();
+ MetaspaceAux::verify_metrics();
BiasedLocking::restore_marks();
Threads::gc_epilogue();
@@ -340,8 +340,7 @@
if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
- gclog_or_tty->print(" VerifyAfterGC:");
- Universe::verify();
+ Universe::verify(" VerifyAfterGC:");
}
// Re-verify object start arrays
@@ -518,23 +517,23 @@
is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL);
}
- // Follow system dictionary roots and unload classes
+ // This is the point where the entire marking should have completed.
+ assert(_marking_stack.is_empty(), "Marking should have completed");
+
+ // Unload classes and purge the SystemDictionary.
bool purged_class = SystemDictionary::do_unloading(is_alive_closure());
- // Follow code cache roots
+ // Unload nmethods.
CodeCache::do_unloading(is_alive_closure(), purged_class);
- follow_stack(); // Flush marking stack
- // Update subklass/sibling/implementor links of live klasses
- Klass::clean_weak_klass_links(&is_alive);
- assert(_marking_stack.is_empty(), "just drained");
+ // Prune dead klasses from subklass/sibling/implementor lists.
+ Klass::clean_weak_klass_links(is_alive_closure());
- // Visit interned string tables and delete unmarked oops
+ // Delete entries for dead interned strings.
StringTable::unlink(is_alive_closure());
+
// Clean up unreferenced symbols in symbol table.
SymbolTable::unlink();
-
- assert(_marking_stack.is_empty(), "stack should be empty by now");
}
@@ -583,28 +582,27 @@
ClassLoaderDataGraph::clear_claimed_marks();
// General strong roots.
- Universe::oops_do(adjust_root_pointer_closure());
- JNIHandles::oops_do(adjust_root_pointer_closure()); // Global (strong) JNI handles
- CLDToOopClosure adjust_from_cld(adjust_root_pointer_closure());
- Threads::oops_do(adjust_root_pointer_closure(), &adjust_from_cld, NULL);
- ObjectSynchronizer::oops_do(adjust_root_pointer_closure());
- FlatProfiler::oops_do(adjust_root_pointer_closure());
- Management::oops_do(adjust_root_pointer_closure());
- JvmtiExport::oops_do(adjust_root_pointer_closure());
+ Universe::oops_do(adjust_pointer_closure());
+ JNIHandles::oops_do(adjust_pointer_closure()); // Global (strong) JNI handles
+ CLDToOopClosure adjust_from_cld(adjust_pointer_closure());
+ Threads::oops_do(adjust_pointer_closure(), &adjust_from_cld, NULL);
+ ObjectSynchronizer::oops_do(adjust_pointer_closure());
+ FlatProfiler::oops_do(adjust_pointer_closure());
+ Management::oops_do(adjust_pointer_closure());
+ JvmtiExport::oops_do(adjust_pointer_closure());
// SO_AllClasses
- SystemDictionary::oops_do(adjust_root_pointer_closure());
- ClassLoaderDataGraph::oops_do(adjust_root_pointer_closure(), adjust_klass_closure(), true);
- //CodeCache::scavenge_root_nmethods_oops_do(adjust_root_pointer_closure());
+ SystemDictionary::oops_do(adjust_pointer_closure());
+ ClassLoaderDataGraph::oops_do(adjust_pointer_closure(), adjust_klass_closure(), true);
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
// Global (weak) JNI handles
- JNIHandles::weak_oops_do(&always_true, adjust_root_pointer_closure());
+ JNIHandles::weak_oops_do(&always_true, adjust_pointer_closure());
CodeCache::oops_do(adjust_pointer_closure());
- StringTable::oops_do(adjust_root_pointer_closure());
- ref_processor()->weak_oops_do(adjust_root_pointer_closure());
- PSScavenge::reference_processor()->weak_oops_do(adjust_root_pointer_closure());
+ StringTable::oops_do(adjust_pointer_closure());
+ ref_processor()->weak_oops_do(adjust_pointer_closure());
+ PSScavenge::reference_processor()->weak_oops_do(adjust_pointer_closure());
adjust_marks();
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -44,7 +44,6 @@
static KlassClosure* follow_klass_closure() { return &MarkSweep::follow_klass_closure; }
static VoidClosure* follow_stack_closure() { return (VoidClosure*)&MarkSweep::follow_stack_closure; }
static OopClosure* adjust_pointer_closure() { return (OopClosure*)&MarkSweep::adjust_pointer_closure; }
- static OopClosure* adjust_root_pointer_closure() { return (OopClosure*)&MarkSweep::adjust_root_pointer_closure; }
static KlassClosure* adjust_klass_closure() { return &MarkSweep::adjust_klass_closure; }
static BoolObjectClosure* is_alive_closure() { return (BoolObjectClosure*)&MarkSweep::is_alive; }
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -787,12 +787,11 @@
void PSParallelCompact::KeepAliveClosure::do_oop(oop* p) { PSParallelCompact::KeepAliveClosure::do_oop_work(p); }
void PSParallelCompact::KeepAliveClosure::do_oop(narrowOop* p) { PSParallelCompact::KeepAliveClosure::do_oop_work(p); }
-PSParallelCompact::AdjustPointerClosure PSParallelCompact::_adjust_root_pointer_closure(true);
-PSParallelCompact::AdjustPointerClosure PSParallelCompact::_adjust_pointer_closure(false);
+PSParallelCompact::AdjustPointerClosure PSParallelCompact::_adjust_pointer_closure;
PSParallelCompact::AdjustKlassClosure PSParallelCompact::_adjust_klass_closure;
-void PSParallelCompact::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p, _is_root); }
-void PSParallelCompact::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p, _is_root); }
+void PSParallelCompact::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p); }
+void PSParallelCompact::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p); }
void PSParallelCompact::FollowStackClosure::do_void() { _compaction_manager->follow_marking_stacks(); }
@@ -805,7 +804,7 @@
klass->oops_do(_mark_and_push_closure);
}
void PSParallelCompact::AdjustKlassClosure::do_klass(Klass* klass) {
- klass->oops_do(&PSParallelCompact::_adjust_root_pointer_closure);
+ klass->oops_do(&PSParallelCompact::_adjust_pointer_closure);
}
void PSParallelCompact::post_initialize() {
@@ -892,7 +891,7 @@
_heap_used = heap->used();
_young_gen_used = heap->young_gen()->used_in_bytes();
_old_gen_used = heap->old_gen()->used_in_bytes();
- _metadata_used = MetaspaceAux::used_in_bytes();
+ _metadata_used = MetaspaceAux::allocated_used_bytes();
};
size_t heap_used() const { return _heap_used; }
@@ -967,8 +966,7 @@
if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
- gclog_or_tty->print(" VerifyBeforeGC:");
- Universe::verify();
+ Universe::verify(" VerifyBeforeGC:");
}
// Verify object start arrays
@@ -1027,6 +1025,7 @@
// Delete metaspaces for unloaded class loaders and clean up loader_data graph
ClassLoaderDataGraph::purge();
+ MetaspaceAux::verify_metrics();
Threads::gc_epilogue();
CodeCache::gc_epilogue();
@@ -2168,8 +2167,7 @@
if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
- gclog_or_tty->print(" VerifyAfterGC:");
- Universe::verify();
+ Universe::verify(" VerifyAfterGC:");
}
// Re-verify object start arrays
@@ -2356,22 +2354,24 @@
}
TraceTime tm_c("class unloading", print_phases(), true, gclog_or_tty);
+
+ // This is the point where the entire marking should have completed.
+ assert(cm->marking_stacks_empty(), "Marking should have completed");
+
// Follow system dictionary roots and unload classes.
bool purged_class = SystemDictionary::do_unloading(is_alive_closure());
- // Follow code cache roots.
+ // Unload nmethods.
CodeCache::do_unloading(is_alive_closure(), purged_class);
- cm->follow_marking_stacks(); // Flush marking stack.
-
- // Update subklass/sibling/implementor links of live klasses
+
+ // Prune dead klasses from subklass/sibling/implementor lists.
Klass::clean_weak_klass_links(is_alive_closure());
- // Visit interned string tables and delete unmarked oops
+ // Delete entries for dead interned strings.
StringTable::unlink(is_alive_closure());
+
// Clean up unreferenced symbols in symbol table.
SymbolTable::unlink();
-
- assert(cm->marking_stacks_empty(), "marking stacks should be empty");
}
void PSParallelCompact::follow_klass(ParCompactionManager* cm, Klass* klass) {
@@ -2398,7 +2398,7 @@
void PSParallelCompact::adjust_class_loader(ParCompactionManager* cm,
ClassLoaderData* cld) {
- cld->oops_do(PSParallelCompact::adjust_root_pointer_closure(),
+ cld->oops_do(PSParallelCompact::adjust_pointer_closure(),
PSParallelCompact::adjust_klass_closure(),
true);
}
@@ -2419,32 +2419,31 @@
ClassLoaderDataGraph::clear_claimed_marks();
// General strong roots.
- Universe::oops_do(adjust_root_pointer_closure());
- JNIHandles::oops_do(adjust_root_pointer_closure()); // Global (strong) JNI handles
- CLDToOopClosure adjust_from_cld(adjust_root_pointer_closure());
- Threads::oops_do(adjust_root_pointer_closure(), &adjust_from_cld, NULL);
- ObjectSynchronizer::oops_do(adjust_root_pointer_closure());
- FlatProfiler::oops_do(adjust_root_pointer_closure());
- Management::oops_do(adjust_root_pointer_closure());
- JvmtiExport::oops_do(adjust_root_pointer_closure());
+ Universe::oops_do(adjust_pointer_closure());
+ JNIHandles::oops_do(adjust_pointer_closure()); // Global (strong) JNI handles
+ CLDToOopClosure adjust_from_cld(adjust_pointer_closure());
+ Threads::oops_do(adjust_pointer_closure(), &adjust_from_cld, NULL);
+ ObjectSynchronizer::oops_do(adjust_pointer_closure());
+ FlatProfiler::oops_do(adjust_pointer_closure());
+ Management::oops_do(adjust_pointer_closure());
+ JvmtiExport::oops_do(adjust_pointer_closure());
// SO_AllClasses
- SystemDictionary::oops_do(adjust_root_pointer_closure());
- ClassLoaderDataGraph::oops_do(adjust_root_pointer_closure(), adjust_klass_closure(), true);
+ SystemDictionary::oops_do(adjust_pointer_closure());
+ ClassLoaderDataGraph::oops_do(adjust_pointer_closure(), adjust_klass_closure(), true);
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
// Global (weak) JNI handles
- JNIHandles::weak_oops_do(&always_true, adjust_root_pointer_closure());
+ JNIHandles::weak_oops_do(&always_true, adjust_pointer_closure());
CodeCache::oops_do(adjust_pointer_closure());
- StringTable::oops_do(adjust_root_pointer_closure());
- ref_processor()->weak_oops_do(adjust_root_pointer_closure());
+ StringTable::oops_do(adjust_pointer_closure());
+ ref_processor()->weak_oops_do(adjust_pointer_closure());
// Roots were visited so references into the young gen in roots
// may have been scanned. Process them also.
// Should the reference processor have a span that excludes
// young gen objects?
- PSScavenge::reference_processor()->weak_oops_do(
- adjust_root_pointer_closure());
+ PSScavenge::reference_processor()->weak_oops_do(adjust_pointer_closure());
}
void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q,
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -799,16 +799,6 @@
virtual void do_oop(narrowOop* p);
};
- // Current unused
- class FollowRootClosure: public OopsInGenClosure {
- private:
- ParCompactionManager* _compaction_manager;
- public:
- FollowRootClosure(ParCompactionManager* cm) : _compaction_manager(cm) { }
- virtual void do_oop(oop* p);
- virtual void do_oop(narrowOop* p);
- };
-
class FollowStackClosure: public VoidClosure {
private:
ParCompactionManager* _compaction_manager;
@@ -818,10 +808,7 @@
};
class AdjustPointerClosure: public OopClosure {
- private:
- bool _is_root;
public:
- AdjustPointerClosure(bool is_root) : _is_root(is_root) { }
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
// do not walk from thread stacks to the code cache on this phase
@@ -838,7 +825,6 @@
friend class AdjustPointerClosure;
friend class AdjustKlassClosure;
friend class FollowKlassClosure;
- friend class FollowRootClosure;
friend class InstanceClassLoaderKlass;
friend class RefProcTaskProxy;
@@ -853,7 +839,6 @@
static IsAliveClosure _is_alive_closure;
static SpaceInfo _space_info[last_space_id];
static bool _print_phases;
- static AdjustPointerClosure _adjust_root_pointer_closure;
static AdjustPointerClosure _adjust_pointer_closure;
static AdjustKlassClosure _adjust_klass_closure;
@@ -889,9 +874,6 @@
static void marking_phase(ParCompactionManager* cm,
bool maximum_heap_compaction);
- template <class T> static inline void adjust_pointer(T* p, bool is_root);
- static void adjust_root_pointer(oop* p) { adjust_pointer(p, true); }
-
template <class T>
static inline void follow_root(ParCompactionManager* cm, T* p);
@@ -1046,7 +1028,6 @@
// Closure accessors
static OopClosure* adjust_pointer_closure() { return (OopClosure*)&_adjust_pointer_closure; }
- static OopClosure* adjust_root_pointer_closure() { return (OopClosure*)&_adjust_root_pointer_closure; }
static KlassClosure* adjust_klass_closure() { return (KlassClosure*)&_adjust_klass_closure; }
static BoolObjectClosure* is_alive_closure() { return (BoolObjectClosure*)&_is_alive_closure; }
@@ -1067,6 +1048,7 @@
// Check mark and maybe push on marking stack
template <class T> static inline void mark_and_push(ParCompactionManager* cm,
T* p);
+ template <class T> static inline void adjust_pointer(T* p);
static void follow_klass(ParCompactionManager* cm, Klass* klass);
static void adjust_klass(ParCompactionManager* cm, Klass* klass);
@@ -1151,9 +1133,6 @@
static ParMarkBitMap* mark_bitmap() { return &_mark_bitmap; }
static ParallelCompactData& summary_data() { return _summary_data; }
- static inline void adjust_pointer(oop* p) { adjust_pointer(p, false); }
- static inline void adjust_pointer(narrowOop* p) { adjust_pointer(p, false); }
-
// Reference Processing
static ReferenceProcessor* const ref_processor() { return _ref_processor; }
@@ -1230,7 +1209,7 @@
}
template <class T>
-inline void PSParallelCompact::adjust_pointer(T* p, bool isroot) {
+inline void PSParallelCompact::adjust_pointer(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -314,8 +314,7 @@
if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
- gclog_or_tty->print(" VerifyBeforeGC:");
- Universe::verify();
+ Universe::verify(" VerifyBeforeGC:");
}
{
@@ -638,8 +637,7 @@
if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
- gclog_or_tty->print(" VerifyAfterGC:");
- Universe::verify();
+ Universe::verify(" VerifyAfterGC:");
}
heap->print_heap_after_gc();
--- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -81,7 +81,7 @@
}
void MarkSweep::adjust_class_loader(ClassLoaderData* cld) {
- cld->oops_do(&MarkSweep::adjust_root_pointer_closure, &MarkSweep::adjust_klass_closure, true);
+ cld->oops_do(&MarkSweep::adjust_pointer_closure, &MarkSweep::adjust_klass_closure, true);
}
@@ -121,11 +121,10 @@
}
}
-MarkSweep::AdjustPointerClosure MarkSweep::adjust_root_pointer_closure(true);
-MarkSweep::AdjustPointerClosure MarkSweep::adjust_pointer_closure(false);
+MarkSweep::AdjustPointerClosure MarkSweep::adjust_pointer_closure;
-void MarkSweep::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p, _is_root); }
-void MarkSweep::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p, _is_root); }
+void MarkSweep::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p); }
+void MarkSweep::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p); }
void MarkSweep::adjust_marks() {
assert( _preserved_oop_stack.size() == _preserved_mark_stack.size(),
--- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -80,10 +80,7 @@
};
class AdjustPointerClosure: public OopsInGenClosure {
- private:
- bool _is_root;
public:
- AdjustPointerClosure(bool is_root) : _is_root(is_root) {}
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
};
@@ -146,7 +143,6 @@
static MarkAndPushClosure mark_and_push_closure;
static FollowKlassClosure follow_klass_closure;
static FollowStackClosure follow_stack_closure;
- static AdjustPointerClosure adjust_root_pointer_closure;
static AdjustPointerClosure adjust_pointer_closure;
static AdjustKlassClosure adjust_klass_closure;
@@ -179,12 +175,7 @@
static void adjust_marks(); // Adjust the pointers in the preserved marks table
static void restore_marks(); // Restore the marks that we saved in preserve_mark
- template <class T> static inline void adjust_pointer(T* p, bool isroot);
-
- static void adjust_root_pointer(oop* p) { adjust_pointer(p, true); }
- static void adjust_pointer(oop* p) { adjust_pointer(p, false); }
- static void adjust_pointer(narrowOop* p) { adjust_pointer(p, false); }
-
+ template <class T> static inline void adjust_pointer(T* p);
};
class PreservedMark VALUE_OBJ_CLASS_SPEC {
--- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -76,7 +76,7 @@
_objarray_stack.push(task);
}
-template <class T> inline void MarkSweep::adjust_pointer(T* p, bool isroot) {
+template <class T> inline void MarkSweep::adjust_pointer(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
--- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -225,7 +225,10 @@
gclog_or_tty->print_cr("\nCMS full GC for Metaspace");
}
heap->collect_as_vm_thread(GCCause::_metadata_GC_threshold);
- _result = _loader_data->metaspace_non_null()->allocate(_size, _mdtype);
+ // After a GC try to allocate without expanding. Could fail
+ // and expansion will be tried below.
+ _result =
+ _loader_data->metaspace_non_null()->allocate(_size, _mdtype);
}
if (_result == NULL && !UseConcMarkSweepGC /* CMS already tried */) {
// If still failing, allow the Metaspace to expand.
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -1052,7 +1052,7 @@
return;
}
if (set_handler_blob() == NULL) {
- vm_exit_out_of_memory(blob_size, "native signature handlers");
+ vm_exit_out_of_memory(blob_size, OOM_MALLOC_ERROR, "native signature handlers");
}
BufferBlob* bb = BufferBlob::create("Signature Handler Temp Buffer",
--- a/hotspot/src/share/vm/memory/allocation.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/allocation.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -259,7 +259,7 @@
}
if (p == NULL) p = os::malloc(bytes, mtChunk, CURRENT_PC);
if (p == NULL)
- vm_exit_out_of_memory(bytes, "ChunkPool::allocate");
+ vm_exit_out_of_memory(bytes, OOM_MALLOC_ERROR, "ChunkPool::allocate");
return p;
}
@@ -371,7 +371,7 @@
default: {
void *p = os::malloc(bytes, mtChunk, CALLER_PC);
if (p == NULL)
- vm_exit_out_of_memory(bytes, "Chunk::new");
+ vm_exit_out_of_memory(bytes, OOM_MALLOC_ERROR, "Chunk::new");
return p;
}
}
@@ -531,7 +531,7 @@
}
void Arena::signal_out_of_memory(size_t sz, const char* whence) const {
- vm_exit_out_of_memory(sz, whence);
+ vm_exit_out_of_memory(sz, OOM_MALLOC_ERROR, whence);
}
// Grow a new Chunk
--- a/hotspot/src/share/vm/memory/allocation.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/allocation.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -539,6 +539,9 @@
#define NEW_RESOURCE_ARRAY(type, size)\
(type*) resource_allocate_bytes((size) * sizeof(type))
+#define NEW_RESOURCE_ARRAY_RETURN_NULL(type, size)\
+ (type*) resource_allocate_bytes((size) * sizeof(type), AllocFailStrategy::RETURN_NULL)
+
#define NEW_RESOURCE_ARRAY_IN_THREAD(thread, type, size)\
(type*) resource_allocate_bytes(thread, (size) * sizeof(type))
--- a/hotspot/src/share/vm/memory/allocation.inline.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/allocation.inline.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -58,7 +58,9 @@
#ifdef ASSERT
if (PrintMallocFree) trace_heap_malloc(size, "AllocateHeap", p);
#endif
- if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) vm_exit_out_of_memory(size, "AllocateHeap");
+ if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) {
+ vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "AllocateHeap");
+ }
return p;
}
@@ -68,7 +70,9 @@
#ifdef ASSERT
if (PrintMallocFree) trace_heap_malloc(size, "ReallocateHeap", p);
#endif
- if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) vm_exit_out_of_memory(size, "ReallocateHeap");
+ if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) {
+ vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "ReallocateHeap");
+ }
return p;
}
@@ -130,12 +134,12 @@
_addr = os::reserve_memory(_size, NULL, alignment);
if (_addr == NULL) {
- vm_exit_out_of_memory(_size, "Allocator (reserve)");
+ vm_exit_out_of_memory(_size, OOM_MMAP_ERROR, "Allocator (reserve)");
}
bool success = os::commit_memory(_addr, _size, false /* executable */);
if (!success) {
- vm_exit_out_of_memory(_size, "Allocator (commit)");
+ vm_exit_out_of_memory(_size, OOM_MMAP_ERROR, "Allocator (commit)");
}
return (E*)_addr;
--- a/hotspot/src/share/vm/memory/blockOffsetTable.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/blockOffsetTable.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -80,7 +80,7 @@
assert(delta > 0, "just checking");
if (!_vs.expand_by(delta)) {
// Do better than this for Merlin
- vm_exit_out_of_memory(delta, "offset table expansion");
+ vm_exit_out_of_memory(delta, OOM_MMAP_ERROR, "offset table expansion");
}
assert(_vs.high() == high + delta, "invalid expansion");
} else {
--- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -116,7 +116,7 @@
_guard_region = MemRegion((HeapWord*)guard_page, _page_size);
if (!os::commit_memory((char*)guard_page, _page_size, _page_size)) {
// Do better than this for Merlin
- vm_exit_out_of_memory(_page_size, "card table last card");
+ vm_exit_out_of_memory(_page_size, OOM_MMAP_ERROR, "card table last card");
}
*guard_card = last_card;
@@ -292,7 +292,7 @@
if (!os::commit_memory((char*)new_committed.start(),
new_committed.byte_size(), _page_size)) {
// Do better than this for Merlin
- vm_exit_out_of_memory(new_committed.byte_size(),
+ vm_exit_out_of_memory(new_committed.byte_size(), OOM_MMAP_ERROR,
"card table expansion");
}
// Use new_end_aligned (as opposed to new_end_for_commit) because
--- a/hotspot/src/share/vm/memory/filemap.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/filemap.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -238,8 +238,8 @@
void FileMapInfo::write_space(int i, Metaspace* space, bool read_only) {
align_file_position();
- size_t used = space->used_words(Metaspace::NonClassType) * BytesPerWord;
- size_t capacity = space->capacity_words(Metaspace::NonClassType) * BytesPerWord;
+ size_t used = space->used_bytes_slow(Metaspace::NonClassType);
+ size_t capacity = space->capacity_bytes_slow(Metaspace::NonClassType);
struct FileMapInfo::FileMapHeader::space_info* si = &_header._space[i];
write_region(i, (char*)space->bottom(), used, capacity, read_only, false);
}
--- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -377,7 +377,7 @@
ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());
- const size_t metadata_prev_used = MetaspaceAux::used_in_bytes();
+ const size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes();
print_heap_before_gc();
@@ -447,8 +447,7 @@
prepare_for_verify();
prepared_for_verification = true;
}
- gclog_or_tty->print(" VerifyBeforeGC:");
- Universe::verify();
+ Universe::verify(" VerifyBeforeGC:");
}
COMPILER2_PRESENT(DerivedPointerTable::clear());
@@ -519,8 +518,7 @@
if (VerifyAfterGC && i >= VerifyGCLevel &&
total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
- gclog_or_tty->print(" VerifyAfterGC:");
- Universe::verify();
+ Universe::verify(" VerifyAfterGC:");
}
if (PrintGCDetails) {
@@ -556,6 +554,7 @@
if (complete) {
// Delete metaspaces for unloaded class loaders and clean up loader_data graph
ClassLoaderDataGraph::purge();
+ MetaspaceAux::verify_metrics();
// Resize the metaspace capacity after full collections
MetaspaceGC::compute_new_size();
update_full_collections_completed();
@@ -633,9 +632,8 @@
}
void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure,
- CodeBlobClosure* code_roots,
- OopClosure* non_root_closure) {
- SharedHeap::process_weak_roots(root_closure, code_roots, non_root_closure);
+ CodeBlobClosure* code_roots) {
+ SharedHeap::process_weak_roots(root_closure, code_roots);
// "Local" "weak" refs
for (int i = 0; i < _n_gens; i++) {
_gens[i]->ref_processor()->weak_oops_do(root_closure);
--- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -432,8 +432,7 @@
// JNI weak roots, the code cache, system dictionary, symbol table,
// string table, and referents of reachable weak refs.
void gen_process_weak_roots(OopClosure* root_closure,
- CodeBlobClosure* code_roots,
- OopClosure* non_root_closure);
+ CodeBlobClosure* code_roots);
// Set the saved marks of generations, if that makes sense.
// In particular, if any generation might iterate over the oops
--- a/hotspot/src/share/vm/memory/genMarkSweep.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/genMarkSweep.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -223,23 +223,23 @@
&is_alive, &keep_alive, &follow_stack_closure, NULL);
}
- // Follow system dictionary roots and unload classes
+ // This is the point where the entire marking should have completed.
+ assert(_marking_stack.is_empty(), "Marking should have completed");
+
+ // Unload classes and purge the SystemDictionary.
bool purged_class = SystemDictionary::do_unloading(&is_alive);
- // Follow code cache roots
+ // Unload nmethods.
CodeCache::do_unloading(&is_alive, purged_class);
- follow_stack(); // Flush marking stack
- // Update subklass/sibling/implementor links of live klasses
+ // Prune dead klasses from subklass/sibling/implementor lists.
Klass::clean_weak_klass_links(&is_alive);
- assert(_marking_stack.is_empty(), "just drained");
- // Visit interned string tables and delete unmarked oops
+ // Delete entries for dead interned strings.
StringTable::unlink(&is_alive);
+
// Clean up unreferenced symbols in symbol table.
SymbolTable::unlink();
-
- assert(_marking_stack.is_empty(), "stack should be empty by now");
}
@@ -282,11 +282,10 @@
// Need new claim bits for the pointer adjustment tracing.
ClassLoaderDataGraph::clear_claimed_marks();
- // Because the two closures below are created statically, cannot
+ // Because the closure below is created statically, we cannot
// use OopsInGenClosure constructor which takes a generation,
// as the Universe has not been created when the static constructors
// are run.
- adjust_root_pointer_closure.set_orig_generation(gch->get_gen(level));
adjust_pointer_closure.set_orig_generation(gch->get_gen(level));
gch->gen_process_strong_roots(level,
@@ -294,18 +293,17 @@
true, // activate StrongRootsScope
false, // not scavenging
SharedHeap::SO_AllClasses,
- &adjust_root_pointer_closure,
+ &adjust_pointer_closure,
false, // do not walk code
- &adjust_root_pointer_closure,
+ &adjust_pointer_closure,
&adjust_klass_closure);
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
CodeBlobToOopClosure adjust_code_pointer_closure(&adjust_pointer_closure,
/*do_marking=*/ false);
- gch->gen_process_weak_roots(&adjust_root_pointer_closure,
- &adjust_code_pointer_closure,
- &adjust_pointer_closure);
+ gch->gen_process_weak_roots(&adjust_pointer_closure,
+ &adjust_code_pointer_closure);
adjust_marks();
GenAdjustPointersClosure blk;
--- a/hotspot/src/share/vm/memory/metachunk.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/metachunk.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -28,6 +28,7 @@
#include "utilities/copy.hpp"
#include "utilities/debug.hpp"
+class VirtualSpaceNode;
//
// Future modification
//
@@ -45,27 +46,30 @@
// Metachunk methods
-Metachunk* Metachunk::initialize(MetaWord* ptr, size_t word_size) {
- // Set bottom, top, and end. Allow space for the Metachunk itself
- Metachunk* chunk = (Metachunk*) ptr;
-
- MetaWord* chunk_bottom = ptr + _overhead;
- chunk->set_bottom(ptr);
- chunk->set_top(chunk_bottom);
- MetaWord* chunk_end = ptr + word_size;
- assert(chunk_end > chunk_bottom, "Chunk must be too small");
- chunk->set_end(chunk_end);
- chunk->set_next(NULL);
- chunk->set_prev(NULL);
- chunk->set_word_size(word_size);
+Metachunk::Metachunk(size_t word_size,
+ VirtualSpaceNode* container) :
+ _word_size(word_size),
+ _bottom(NULL),
+ _end(NULL),
+ _top(NULL),
+ _next(NULL),
+ _prev(NULL),
+ _container(container)
+{
+ _bottom = (MetaWord*)this;
+ _top = (MetaWord*)this + _overhead;
+ _end = (MetaWord*)this + word_size;
#ifdef ASSERT
- size_t data_word_size = pointer_delta(chunk_end, chunk_bottom, sizeof(MetaWord));
- Copy::fill_to_words((HeapWord*) chunk_bottom, data_word_size, metadata_chunk_initialize);
+ set_is_free(false);
+ size_t data_word_size = pointer_delta(end(),
+ top(),
+ sizeof(MetaWord));
+ Copy::fill_to_words((HeapWord*) top(),
+ data_word_size,
+ metadata_chunk_initialize);
#endif
- return chunk;
}
-
MetaWord* Metachunk::allocate(size_t word_size) {
MetaWord* result = NULL;
// If available, bump the pointer to allocate.
--- a/hotspot/src/share/vm/memory/metachunk.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/metachunk.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -41,10 +41,13 @@
// | | | |
// +--------------+ <- bottom ---+ ---+
+class VirtualSpaceNode;
+
class Metachunk VALUE_OBJ_CLASS_SPEC {
// link to support lists of chunks
Metachunk* _next;
Metachunk* _prev;
+ VirtualSpaceNode* _container;
MetaWord* _bottom;
MetaWord* _end;
@@ -61,29 +64,20 @@
// the space.
static size_t _overhead;
- void set_bottom(MetaWord* v) { _bottom = v; }
- void set_end(MetaWord* v) { _end = v; }
- void set_top(MetaWord* v) { _top = v; }
- void set_word_size(size_t v) { _word_size = v; }
public:
-#ifdef ASSERT
- Metachunk() : _bottom(NULL), _end(NULL), _top(NULL), _is_free(false),
- _next(NULL), _prev(NULL) {}
-#else
- Metachunk() : _bottom(NULL), _end(NULL), _top(NULL),
- _next(NULL), _prev(NULL) {}
-#endif
+ Metachunk(size_t word_size , VirtualSpaceNode* container);
// Used to add a Metachunk to a list of Metachunks
void set_next(Metachunk* v) { _next = v; assert(v != this, "Boom");}
void set_prev(Metachunk* v) { _prev = v; assert(v != this, "Boom");}
+ void set_container(VirtualSpaceNode* v) { _container = v; }
MetaWord* allocate(size_t word_size);
- static Metachunk* initialize(MetaWord* ptr, size_t word_size);
// Accessors
Metachunk* next() const { return _next; }
Metachunk* prev() const { return _prev; }
+ VirtualSpaceNode* container() const { return _container; }
MetaWord* bottom() const { return _bottom; }
MetaWord* end() const { return _end; }
MetaWord* top() const { return _top; }
--- a/hotspot/src/share/vm/memory/metaspace.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/metaspace.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -47,7 +47,6 @@
// the free chunk lists
const bool metaspace_slow_verify = false;
-
// Parameters for stress mode testing
const uint metadata_deallocate_a_lot_block = 10;
const uint metadata_deallocate_a_lock_chunk = 3;
@@ -112,6 +111,7 @@
class ChunkManager VALUE_OBJ_CLASS_SPEC {
// Free list of chunks of different sizes.
+ // SpecializedChunk
// SmallChunk
// MediumChunk
// HumongousChunk
@@ -165,6 +165,10 @@
// for special, small, medium, and humongous chunks.
static ChunkIndex list_index(size_t size);
+ // Remove the chunk from its freelist. It is
+ // expected to be on one of the _free_chunks[] lists.
+ void remove_chunk(Metachunk* chunk);
+
// Add the simple linked list of chunks to the freelist of chunks
// of type index.
void return_chunks(ChunkIndex index, Metachunk* chunks);
@@ -215,7 +219,6 @@
void print_on(outputStream* st);
};
-
// Used to manage the free list of Metablocks (a block corresponds
// to the allocation of a quantum of metadata).
class BlockFreelist VALUE_OBJ_CLASS_SPEC {
@@ -255,6 +258,8 @@
ReservedSpace _rs;
VirtualSpace _virtual_space;
MetaWord* _top;
+ // count of chunks contained in this VirtualSpace
+ uintx _container_count;
// Convenience functions for logical bottom and end
MetaWord* bottom() const { return (MetaWord*) _virtual_space.low(); }
@@ -264,10 +269,19 @@
char* low() const { return virtual_space()->low(); }
char* high() const { return virtual_space()->high(); }
+ // The first Metachunk will be allocated at the bottom of the
+ // VirtualSpace
+ Metachunk* first_chunk() { return (Metachunk*) bottom(); }
+
+ void inc_container_count();
+#ifdef ASSERT
+ uint container_count_slow();
+#endif
+
public:
VirtualSpaceNode(size_t byte_size);
- VirtualSpaceNode(ReservedSpace rs) : _top(NULL), _next(NULL), _rs(rs) {}
+ VirtualSpaceNode(ReservedSpace rs) : _top(NULL), _next(NULL), _rs(rs), _container_count(0) {}
~VirtualSpaceNode();
// address of next available space in _virtual_space;
@@ -282,15 +296,22 @@
MemRegion* reserved() { return &_reserved; }
VirtualSpace* virtual_space() const { return (VirtualSpace*) &_virtual_space; }
- // Returns true if "word_size" is available in the virtual space
+ // Returns true if "word_size" is available in the VirtualSpace
bool is_available(size_t word_size) { return _top + word_size <= end(); }
MetaWord* top() const { return _top; }
void inc_top(size_t word_size) { _top += word_size; }
+ uintx container_count() { return _container_count; }
+ void dec_container_count();
+#ifdef ASSERT
+ void verify_container_count();
+#endif
+
// used and capacity in this single entry in the list
size_t used_words_in_vs() const;
size_t capacity_words_in_vs() const;
+ size_t free_words_in_vs() const;
bool initialize();
@@ -306,6 +327,10 @@
bool expand_by(size_t words, bool pre_touch = false);
bool shrink_by(size_t words);
+ // In preparation for deleting this node, remove all the chunks
+ // in the node from any freelist.
+ void purge(ChunkManager* chunk_manager);
+
#ifdef ASSERT
// Debug support
static void verify_virtual_space_total();
@@ -317,7 +342,7 @@
};
// byte_size is the size of the associated virtualspace.
-VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0) {
+VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0), _container_count(0) {
// align up to vm allocation granularity
byte_size = align_size_up(byte_size, os::vm_allocation_granularity());
@@ -341,6 +366,39 @@
MemTracker::record_virtual_memory_type((address)_rs.base(), mtClass);
}
+void VirtualSpaceNode::purge(ChunkManager* chunk_manager) {
+ Metachunk* chunk = first_chunk();
+ Metachunk* invalid_chunk = (Metachunk*) top();
+ while (chunk < invalid_chunk ) {
+ assert(chunk->is_free(), "Should be marked free");
+ MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
+ chunk_manager->remove_chunk(chunk);
+ assert(chunk->next() == NULL &&
+ chunk->prev() == NULL,
+ "Was not removed from its list");
+ chunk = (Metachunk*) next;
+ }
+}
+
+#ifdef ASSERT
+uint VirtualSpaceNode::container_count_slow() {
+ uint count = 0;
+ Metachunk* chunk = first_chunk();
+ Metachunk* invalid_chunk = (Metachunk*) top();
+ while (chunk < invalid_chunk ) {
+ MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
+ // Don't count the chunks on the free lists. Those are
+ // still part of the VirtualSpaceNode but not currently
+ // counted.
+ if (!chunk->is_free()) {
+ count++;
+ }
+ chunk = (Metachunk*) next;
+ }
+ return count;
+}
+#endif
+
// List of VirtualSpaces for metadata allocation.
// It has a _next link for singly linked list and a MemRegion
// for total space in the VirtualSpace.
@@ -390,6 +448,8 @@
VirtualSpaceList(size_t word_size);
VirtualSpaceList(ReservedSpace rs);
+ size_t free_bytes();
+
Metachunk* get_new_chunk(size_t word_size,
size_t grow_chunks_by_words,
size_t medium_chunk_bunch);
@@ -410,14 +470,14 @@
void initialize(size_t word_size);
size_t virtual_space_total() { return _virtual_space_total; }
- void inc_virtual_space_total(size_t v) {
- Atomic::add_ptr(v, &_virtual_space_total);
- }
-
- size_t virtual_space_count() { return _virtual_space_count; }
- void inc_virtual_space_count() {
- Atomic::inc_ptr(&_virtual_space_count);
- }
+
+ void inc_virtual_space_total(size_t v);
+ void dec_virtual_space_total(size_t v);
+ void inc_virtual_space_count();
+ void dec_virtual_space_count();
+
+ // Unlink empty VirtualSpaceNodes and free it.
+ void purge();
// Used and capacity in the entire list of virtual spaces.
// These are global values shared by all Metaspaces
@@ -520,7 +580,11 @@
bool has_small_chunk_limit() { return !vs_list()->is_class(); }
// Sum of all space in allocated chunks
- size_t _allocation_total;
+ size_t _allocated_blocks_words;
+
+ // Sum of all allocated chunks
+ size_t _allocated_chunks_words;
+ size_t _allocated_chunks_count;
// Free lists of blocks are per SpaceManager since they
// are assumed to be in chunks in use by the SpaceManager
@@ -576,12 +640,27 @@
size_t medium_chunk_size() { return (size_t) vs_list()->is_class() ? ClassMediumChunk : MediumChunk; }
size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; }
- size_t allocation_total() const { return _allocation_total; }
- void inc_allocation_total(size_t v) { Atomic::add_ptr(v, &_allocation_total); }
+ size_t allocated_blocks_words() const { return _allocated_blocks_words; }
+ size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; }
+ size_t allocated_chunks_words() const { return _allocated_chunks_words; }
+ size_t allocated_chunks_count() const { return _allocated_chunks_count; }
+
bool is_humongous(size_t word_size) { return word_size > medium_chunk_size(); }
static Mutex* expand_lock() { return _expand_lock; }
+ // Increment the per Metaspace and global running sums for Metachunks
+ // by the given size. This is used when a Metachunk to added to
+ // the in-use list.
+ void inc_size_metrics(size_t words);
+ // Increment the per Metaspace and global running sums Metablocks by the given
+ // size. This is used when a Metablock is allocated.
+ void inc_used_metrics(size_t words);
+ // Delete the portion of the running sums for this SpaceManager. That is,
+ // the globals running sums for the Metachunks and Metablocks are
+ // decremented for all the Metachunks in-use by this SpaceManager.
+ void dec_total_from_size_metrics();
+
// Set the sizes for the initial chunks.
void get_initial_chunk_sizes(Metaspace::MetaspaceType type,
size_t* chunk_word_size,
@@ -627,7 +706,7 @@
void verify_chunk_size(Metachunk* chunk);
NOT_PRODUCT(void mangle_freed_chunks();)
#ifdef ASSERT
- void verify_allocation_total();
+ void verify_allocated_blocks_words();
#endif
};
@@ -641,6 +720,28 @@
SpaceManager::_expand_lock_name,
Mutex::_allow_vm_block_flag);
+void VirtualSpaceNode::inc_container_count() {
+ assert_lock_strong(SpaceManager::expand_lock());
+ _container_count++;
+ assert(_container_count == container_count_slow(),
+ err_msg("Inconsistency in countainer_count _container_count " SIZE_FORMAT
+ "container_count_slow() " SIZE_FORMAT,
+ _container_count, container_count_slow()));
+}
+
+void VirtualSpaceNode::dec_container_count() {
+ assert_lock_strong(SpaceManager::expand_lock());
+ _container_count--;
+}
+
+#ifdef ASSERT
+void VirtualSpaceNode::verify_container_count() {
+ assert(_container_count == container_count_slow(),
+ err_msg("Inconsistency in countainer_count _container_count " SIZE_FORMAT
+ "container_count_slow() " SIZE_FORMAT, _container_count, container_count_slow()));
+}
+#endif
+
// BlockFreelist methods
BlockFreelist::BlockFreelist() : _dictionary(NULL) {}
@@ -701,6 +802,10 @@
VirtualSpaceNode::~VirtualSpaceNode() {
_rs.release();
+#ifdef ASSERT
+ size_t word_size = sizeof(*this) / BytesPerWord;
+ Copy::fill_to_words((HeapWord*) this, word_size, 0xf1f1f1f1);
+#endif
}
size_t VirtualSpaceNode::used_words_in_vs() const {
@@ -712,6 +817,9 @@
return pointer_delta(end(), bottom(), sizeof(MetaWord));
}
+size_t VirtualSpaceNode::free_words_in_vs() const {
+ return pointer_delta(end(), top(), sizeof(MetaWord));
+}
// Allocates the chunk from the virtual space only.
// This interface is also used internally for debugging. Not all
@@ -733,8 +841,8 @@
// Take the space (bump top on the current virtual space).
inc_top(chunk_word_size);
- // Point the chunk at the space
- Metachunk* result = Metachunk::initialize(chunk_limit, chunk_word_size);
+ // Initialize the chunk
+ Metachunk* result = ::new (chunk_limit) Metachunk(chunk_word_size, this);
return result;
}
@@ -762,9 +870,11 @@
Metachunk* VirtualSpaceNode::get_chunk_vs(size_t chunk_word_size) {
assert_lock_strong(SpaceManager::expand_lock());
- Metachunk* result = NULL;
-
- return take_from_committed(chunk_word_size);
+ Metachunk* result = take_from_committed(chunk_word_size);
+ if (result != NULL) {
+ inc_container_count();
+ }
+ return result;
}
Metachunk* VirtualSpaceNode::get_chunk_vs_with_expand(size_t chunk_word_size) {
@@ -843,6 +953,83 @@
}
}
+void VirtualSpaceList::inc_virtual_space_total(size_t v) {
+ assert_lock_strong(SpaceManager::expand_lock());
+ _virtual_space_total = _virtual_space_total + v;
+}
+void VirtualSpaceList::dec_virtual_space_total(size_t v) {
+ assert_lock_strong(SpaceManager::expand_lock());
+ _virtual_space_total = _virtual_space_total - v;
+}
+
+void VirtualSpaceList::inc_virtual_space_count() {
+ assert_lock_strong(SpaceManager::expand_lock());
+ _virtual_space_count++;
+}
+void VirtualSpaceList::dec_virtual_space_count() {
+ assert_lock_strong(SpaceManager::expand_lock());
+ _virtual_space_count--;
+}
+
+void ChunkManager::remove_chunk(Metachunk* chunk) {
+ size_t word_size = chunk->word_size();
+ ChunkIndex index = list_index(word_size);
+ if (index != HumongousIndex) {
+ free_chunks(index)->remove_chunk(chunk);
+ } else {
+ humongous_dictionary()->remove_chunk(chunk);
+ }
+
+ // Chunk is being removed from the chunks free list.
+ dec_free_chunks_total(chunk->capacity_word_size());
+}
+
+// Walk the list of VirtualSpaceNodes and delete
+// nodes with a 0 container_count. Remove Metachunks in
+// the node from their respective freelists.
+void VirtualSpaceList::purge() {
+ assert_lock_strong(SpaceManager::expand_lock());
+ // Don't use a VirtualSpaceListIterator because this
+ // list is being changed and a straightforward use of an iterator is not safe.
+ VirtualSpaceNode* purged_vsl = NULL;
+ VirtualSpaceNode* prev_vsl = virtual_space_list();
+ VirtualSpaceNode* next_vsl = prev_vsl;
+ while (next_vsl != NULL) {
+ VirtualSpaceNode* vsl = next_vsl;
+ next_vsl = vsl->next();
+ // Don't free the current virtual space since it will likely
+ // be needed soon.
+ if (vsl->container_count() == 0 && vsl != current_virtual_space()) {
+ // Unlink it from the list
+ if (prev_vsl == vsl) {
+ // This is the case of the current note being the first note.
+ assert(vsl == virtual_space_list(), "Expected to be the first note");
+ set_virtual_space_list(vsl->next());
+ } else {
+ prev_vsl->set_next(vsl->next());
+ }
+
+ vsl->purge(chunk_manager());
+ dec_virtual_space_total(vsl->reserved()->word_size());
+ dec_virtual_space_count();
+ purged_vsl = vsl;
+ delete vsl;
+ } else {
+ prev_vsl = vsl;
+ }
+ }
+#ifdef ASSERT
+ if (purged_vsl != NULL) {
+ // List should be stable enough to use an iterator here.
+ VirtualSpaceListIterator iter(virtual_space_list());
+ while (iter.repeat()) {
+ VirtualSpaceNode* vsl = iter.get_next();
+ assert(vsl != purged_vsl, "Purge of vsl failed");
+ }
+ }
+#endif
+}
+
size_t VirtualSpaceList::used_words_sum() {
size_t allocated_by_vs = 0;
VirtualSpaceListIterator iter(virtual_space_list());
@@ -907,6 +1094,10 @@
link_vs(class_entry, rs.size()/BytesPerWord);
}
+size_t VirtualSpaceList::free_bytes() {
+ return virtual_space_list()->free_words_in_vs() * BytesPerWord;
+}
+
// Allocate another meta virtual space and add it to the list.
bool VirtualSpaceList::grow_vs(size_t vs_word_size) {
assert_lock_strong(SpaceManager::expand_lock());
@@ -955,8 +1146,10 @@
// Get a chunk from the chunk freelist
Metachunk* next = chunk_manager()->chunk_freelist_allocate(grow_chunks_by_words);
- // Allocate a chunk out of the current virtual space.
- if (next == NULL) {
+ if (next != NULL) {
+ next->container()->inc_container_count();
+ } else {
+ // Allocate a chunk out of the current virtual space.
next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words);
}
@@ -1045,9 +1238,9 @@
//
// After the GC the compute_new_size() for MetaspaceGC is called to
// resize the capacity of the metaspaces. The current implementation
-// is based on the flags MinMetaspaceFreeRatio and MaxHeapFreeRatio used
+// is based on the flags MinMetaspaceFreeRatio and MaxMetaspaceFreeRatio used
// to resize the Java heap by some GC's. New flags can be implemented
-// if really needed. MinHeapFreeRatio is used to calculate how much
+// if really needed. MinMetaspaceFreeRatio is used to calculate how much
// free space is desirable in the metaspace capacity to decide how much
// to increase the HWM. MaxMetaspaceFreeRatio is used to decide how much
// free space is desirable in the metaspace capacity before decreasing
@@ -1082,7 +1275,11 @@
}
bool MetaspaceGC::should_expand(VirtualSpaceList* vsl, size_t word_size) {
+
+ size_t committed_capacity_bytes = MetaspaceAux::allocated_capacity_bytes();
// If the user wants a limit, impose one.
+ size_t max_metaspace_size_bytes = MaxMetaspaceSize;
+ size_t metaspace_size_bytes = MetaspaceSize;
if (!FLAG_IS_DEFAULT(MaxMetaspaceSize) &&
MetaspaceAux::reserved_in_bytes() >= MaxMetaspaceSize) {
return false;
@@ -1094,57 +1291,48 @@
// If this is part of an allocation after a GC, expand
// unconditionally.
- if(MetaspaceGC::expand_after_GC()) {
+ if (MetaspaceGC::expand_after_GC()) {
return true;
}
- size_t metaspace_size_words = MetaspaceSize / BytesPerWord;
+
// If the capacity is below the minimum capacity, allow the
// expansion. Also set the high-water-mark (capacity_until_GC)
// to that minimum capacity so that a GC will not be induced
// until that minimum capacity is exceeded.
- if (vsl->capacity_words_sum() < metaspace_size_words ||
+ if (committed_capacity_bytes < metaspace_size_bytes ||
capacity_until_GC() == 0) {
- set_capacity_until_GC(metaspace_size_words);
+ set_capacity_until_GC(metaspace_size_bytes);
return true;
} else {
- if (vsl->capacity_words_sum() < capacity_until_GC()) {
+ if (committed_capacity_bytes < capacity_until_GC()) {
return true;
} else {
if (TraceMetadataChunkAllocation && Verbose) {
gclog_or_tty->print_cr(" allocation request size " SIZE_FORMAT
" capacity_until_GC " SIZE_FORMAT
- " capacity_words_sum " SIZE_FORMAT
- " used_words_sum " SIZE_FORMAT
- " free chunks " SIZE_FORMAT
- " free chunks count %d",
+ " allocated_capacity_bytes " SIZE_FORMAT,
word_size,
capacity_until_GC(),
- vsl->capacity_words_sum(),
- vsl->used_words_sum(),
- vsl->chunk_manager()->free_chunks_total(),
- vsl->chunk_manager()->free_chunks_count());
+ MetaspaceAux::allocated_capacity_bytes());
}
return false;
}
}
}
-// Variables are in bytes
+
void MetaspaceGC::compute_new_size() {
assert(_shrink_factor <= 100, "invalid shrink factor");
uint current_shrink_factor = _shrink_factor;
_shrink_factor = 0;
- VirtualSpaceList *vsl = Metaspace::space_list();
-
- size_t capacity_after_gc = vsl->capacity_bytes_sum();
- // Check to see if these two can be calculated without walking the CLDG
- size_t used_after_gc = vsl->used_bytes_sum();
- size_t capacity_until_GC = vsl->capacity_bytes_sum();
- size_t free_after_gc = capacity_until_GC - used_after_gc;
+ // Until a faster way of calculating the "used" quantity is implemented,
+ // use "capacity".
+ const size_t used_after_gc = MetaspaceAux::allocated_capacity_bytes();
+ const size_t capacity_until_GC = MetaspaceGC::capacity_until_GC();
const double minimum_free_percentage = MinMetaspaceFreeRatio / 100.0;
const double maximum_used_percentage = 1.0 - minimum_free_percentage;
@@ -1157,45 +1345,34 @@
MetaspaceSize);
if (PrintGCDetails && Verbose) {
- const double free_percentage = ((double)free_after_gc) / capacity_until_GC;
gclog_or_tty->print_cr("\nMetaspaceGC::compute_new_size: ");
gclog_or_tty->print_cr(" "
" minimum_free_percentage: %6.2f"
" maximum_used_percentage: %6.2f",
minimum_free_percentage,
maximum_used_percentage);
- double d_free_after_gc = free_after_gc / (double) K;
gclog_or_tty->print_cr(" "
- " free_after_gc : %6.1fK"
- " used_after_gc : %6.1fK"
- " capacity_after_gc : %6.1fK"
- " metaspace HWM : %6.1fK",
- free_after_gc / (double) K,
- used_after_gc / (double) K,
- capacity_after_gc / (double) K,
- capacity_until_GC / (double) K);
- gclog_or_tty->print_cr(" "
- " free_percentage: %6.2f",
- free_percentage);
+ " used_after_gc : %6.1fKB",
+ used_after_gc / (double) K);
}
+ size_t shrink_bytes = 0;
if (capacity_until_GC < minimum_desired_capacity) {
// If we have less capacity below the metaspace HWM, then
// increment the HWM.
size_t expand_bytes = minimum_desired_capacity - capacity_until_GC;
// Don't expand unless it's significant
if (expand_bytes >= MinMetaspaceExpansion) {
- size_t expand_words = expand_bytes / BytesPerWord;
- MetaspaceGC::inc_capacity_until_GC(expand_words);
+ MetaspaceGC::set_capacity_until_GC(capacity_until_GC + expand_bytes);
}
if (PrintGCDetails && Verbose) {
- size_t new_capacity_until_GC = MetaspaceGC::capacity_until_GC_in_bytes();
+ size_t new_capacity_until_GC = capacity_until_GC;
gclog_or_tty->print_cr(" expanding:"
- " minimum_desired_capacity: %6.1fK"
- " expand_words: %6.1fK"
- " MinMetaspaceExpansion: %6.1fK"
- " new metaspace HWM: %6.1fK",
+ " minimum_desired_capacity: %6.1fKB"
+ " expand_bytes: %6.1fKB"
+ " MinMetaspaceExpansion: %6.1fKB"
+ " new metaspace HWM: %6.1fKB",
minimum_desired_capacity / (double) K,
expand_bytes / (double) K,
MinMetaspaceExpansion / (double) K,
@@ -1205,11 +1382,10 @@
}
// No expansion, now see if we want to shrink
- size_t shrink_words = 0;
// We would never want to shrink more than this
- size_t max_shrink_words = capacity_until_GC - minimum_desired_capacity;
- assert(max_shrink_words >= 0, err_msg("max_shrink_words " SIZE_FORMAT,
- max_shrink_words));
+ size_t max_shrink_bytes = capacity_until_GC - minimum_desired_capacity;
+ assert(max_shrink_bytes >= 0, err_msg("max_shrink_bytes " SIZE_FORMAT,
+ max_shrink_bytes));
// Should shrinking be considered?
if (MaxMetaspaceFreeRatio < 100) {
@@ -1219,17 +1395,15 @@
size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx));
maximum_desired_capacity = MAX2(maximum_desired_capacity,
MetaspaceSize);
- if (PrintGC && Verbose) {
+ if (PrintGCDetails && Verbose) {
gclog_or_tty->print_cr(" "
" maximum_free_percentage: %6.2f"
" minimum_used_percentage: %6.2f",
maximum_free_percentage,
minimum_used_percentage);
gclog_or_tty->print_cr(" "
- " capacity_until_GC: %6.1fK"
- " minimum_desired_capacity: %6.1fK"
- " maximum_desired_capacity: %6.1fK",
- capacity_until_GC / (double) K,
+ " minimum_desired_capacity: %6.1fKB"
+ " maximum_desired_capacity: %6.1fKB",
minimum_desired_capacity / (double) K,
maximum_desired_capacity / (double) K);
}
@@ -1239,17 +1413,17 @@
if (capacity_until_GC > maximum_desired_capacity) {
// Capacity too large, compute shrinking size
- shrink_words = capacity_until_GC - maximum_desired_capacity;
+ shrink_bytes = capacity_until_GC - maximum_desired_capacity;
// We don't want shrink all the way back to initSize if people call
// System.gc(), because some programs do that between "phases" and then
// we'd just have to grow the heap up again for the next phase. So we
// damp the shrinking: 0% on the first call, 10% on the second call, 40%
// on the third call, and 100% by the fourth call. But if we recompute
// size without shrinking, it goes back to 0%.
- shrink_words = shrink_words / 100 * current_shrink_factor;
- assert(shrink_words <= max_shrink_words,
+ shrink_bytes = shrink_bytes / 100 * current_shrink_factor;
+ assert(shrink_bytes <= max_shrink_bytes,
err_msg("invalid shrink size " SIZE_FORMAT " not <= " SIZE_FORMAT,
- shrink_words, max_shrink_words));
+ shrink_bytes, max_shrink_bytes));
if (current_shrink_factor == 0) {
_shrink_factor = 10;
} else {
@@ -1263,11 +1437,11 @@
MetaspaceSize / (double) K,
maximum_desired_capacity / (double) K);
gclog_or_tty->print_cr(" "
- " shrink_words: %.1fK"
+ " shrink_bytes: %.1fK"
" current_shrink_factor: %d"
" new shrink factor: %d"
" MinMetaspaceExpansion: %.1fK",
- shrink_words / (double) K,
+ shrink_bytes / (double) K,
current_shrink_factor,
_shrink_factor,
MinMetaspaceExpansion / (double) K);
@@ -1275,23 +1449,11 @@
}
}
-
// Don't shrink unless it's significant
- if (shrink_words >= MinMetaspaceExpansion) {
- VirtualSpaceNode* csp = vsl->current_virtual_space();
- size_t available_to_shrink = csp->capacity_words_in_vs() -
- csp->used_words_in_vs();
- shrink_words = MIN2(shrink_words, available_to_shrink);
- csp->shrink_by(shrink_words);
- MetaspaceGC::dec_capacity_until_GC(shrink_words);
- if (PrintGCDetails && Verbose) {
- size_t new_capacity_until_GC = MetaspaceGC::capacity_until_GC_in_bytes();
- gclog_or_tty->print_cr(" metaspace HWM: %.1fK", new_capacity_until_GC / (double) K);
- }
+ if (shrink_bytes >= MinMetaspaceExpansion &&
+ ((capacity_until_GC - shrink_bytes) >= MetaspaceSize)) {
+ MetaspaceGC::set_capacity_until_GC(capacity_until_GC - shrink_bytes);
}
- assert(used_after_gc <= vsl->capacity_bytes_sum(),
- "sanity check");
-
}
// Metadebug methods
@@ -1567,9 +1729,6 @@
}
// Chunk is being removed from the chunks free list.
dec_free_chunks_total(chunk->capacity_word_size());
-#ifdef ASSERT
- chunk->set_is_free(false);
-#endif
} else {
return NULL;
}
@@ -1578,6 +1737,11 @@
// Remove it from the links to this freelist
chunk->set_next(NULL);
chunk->set_prev(NULL);
+#ifdef ASSERT
+ // Chunk is no longer on any freelist. Setting to false make container_count_slow()
+ // work.
+ chunk->set_is_free(false);
+#endif
slow_locked_verify();
return chunk;
}
@@ -1692,18 +1856,28 @@
}
size_t SpaceManager::sum_capacity_in_chunks_in_use() const {
- MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
- size_t sum = 0;
- for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
- Metachunk* chunk = chunks_in_use(i);
- while (chunk != NULL) {
- // Just changed this sum += chunk->capacity_word_size();
- // sum += chunk->word_size() - Metachunk::overhead();
- sum += chunk->capacity_word_size();
- chunk = chunk->next();
+ // For CMS use "allocated_chunks_words()" which does not need the
+ // Metaspace lock. For the other collectors sum over the
+ // lists. Use both methods as a check that "allocated_chunks_words()"
+ // is correct. That is, sum_capacity_in_chunks() is too expensive
+ // to use in the product and allocated_chunks_words() should be used
+ // but allow for checking that allocated_chunks_words() returns the same
+ // value as sum_capacity_in_chunks_in_use() which is the definitive
+ // answer.
+ if (UseConcMarkSweepGC) {
+ return allocated_chunks_words();
+ } else {
+ MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
+ size_t sum = 0;
+ for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
+ Metachunk* chunk = chunks_in_use(i);
+ while (chunk != NULL) {
+ sum += chunk->capacity_word_size();
+ chunk = chunk->next();
+ }
}
+ return sum;
}
- return sum;
}
size_t SpaceManager::sum_count_in_chunks_in_use() {
@@ -1861,12 +2035,44 @@
SpaceManager::SpaceManager(Mutex* lock,
VirtualSpaceList* vs_list) :
_vs_list(vs_list),
- _allocation_total(0),
+ _allocated_blocks_words(0),
+ _allocated_chunks_words(0),
+ _allocated_chunks_count(0),
_lock(lock)
{
initialize();
}
+void SpaceManager::inc_size_metrics(size_t words) {
+ assert_lock_strong(SpaceManager::expand_lock());
+ // Total of allocated Metachunks and allocated Metachunks count
+ // for each SpaceManager
+ _allocated_chunks_words = _allocated_chunks_words + words;
+ _allocated_chunks_count++;
+ // Global total of capacity in allocated Metachunks
+ MetaspaceAux::inc_capacity(words);
+ // Global total of allocated Metablocks.
+ // used_words_slow() includes the overhead in each
+ // Metachunk so include it in the used when the
+ // Metachunk is first added (so only added once per
+ // Metachunk).
+ MetaspaceAux::inc_used(Metachunk::overhead());
+}
+
+void SpaceManager::inc_used_metrics(size_t words) {
+ // Add to the per SpaceManager total
+ Atomic::add_ptr(words, &_allocated_blocks_words);
+ // Add to the global total
+ MetaspaceAux::inc_used(words);
+}
+
+void SpaceManager::dec_total_from_size_metrics() {
+ MetaspaceAux::dec_capacity(allocated_chunks_words());
+ MetaspaceAux::dec_used(allocated_blocks_words());
+ // Also deduct the overhead per Metachunk
+ MetaspaceAux::dec_used(allocated_chunks_count() * Metachunk::overhead());
+}
+
void SpaceManager::initialize() {
Metadebug::init_allocation_fail_alot_count();
for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
@@ -1887,11 +2093,13 @@
assert_lock_strong(SpaceManager::expand_lock());
Metachunk* cur = chunks;
- // This return chunks one at a time. If a new
+ // This returns chunks one at a time. If a new
// class List can be created that is a base class
// of FreeList then something like FreeList::prepend()
// can be used in place of this loop
while (cur != NULL) {
+ assert(cur->container() != NULL, "Container should have been set");
+ cur->container()->dec_container_count();
// Capture the next link before it is changed
// by the call to return_chunk_at_head();
Metachunk* next = cur->next();
@@ -1903,7 +2111,10 @@
SpaceManager::~SpaceManager() {
// This call this->_lock which can't be done while holding expand_lock()
- const size_t in_use_before = sum_capacity_in_chunks_in_use();
+ assert(sum_capacity_in_chunks_in_use() == allocated_chunks_words(),
+ err_msg("sum_capacity_in_chunks_in_use() " SIZE_FORMAT
+ " allocated_chunks_words() " SIZE_FORMAT,
+ sum_capacity_in_chunks_in_use(), allocated_chunks_words()));
MutexLockerEx fcl(SpaceManager::expand_lock(),
Mutex::_no_safepoint_check_flag);
@@ -1912,17 +2123,19 @@
chunk_manager->slow_locked_verify();
+ dec_total_from_size_metrics();
+
if (TraceMetadataChunkAllocation && Verbose) {
gclog_or_tty->print_cr("~SpaceManager(): " PTR_FORMAT, this);
locked_print_chunks_in_use_on(gclog_or_tty);
}
- // Mangle freed memory.
- NOT_PRODUCT(mangle_freed_chunks();)
+ // Do not mangle freed Metachunks. The chunk size inside Metachunks
+ // is during the freeing of a VirtualSpaceNodes.
// Have to update before the chunks_in_use lists are emptied
// below.
- chunk_manager->inc_free_chunks_total(in_use_before,
+ chunk_manager->inc_free_chunks_total(allocated_chunks_words(),
sum_count_in_chunks_in_use());
// Add all the chunks in use by this space manager
@@ -1978,6 +2191,7 @@
" granularity %d",
humongous_chunks->word_size(), HumongousChunkGranularity));
Metachunk* next_humongous_chunks = humongous_chunks->next();
+ humongous_chunks->container()->dec_container_count();
chunk_manager->humongous_dictionary()->return_chunk(humongous_chunks);
humongous_chunks = next_humongous_chunks;
}
@@ -1987,7 +2201,6 @@
chunk_manager->humongous_dictionary()->total_count(),
chunk_size_name(HumongousIndex));
}
- set_chunks_in_use(HumongousIndex, NULL);
chunk_manager->slow_locked_verify();
}
@@ -2067,12 +2280,17 @@
assert(new_chunk->word_size() > medium_chunk_size(), "List inconsistency");
}
+ // Add to the running sum of capacity
+ inc_size_metrics(new_chunk->word_size());
+
assert(new_chunk->is_empty(), "Not ready for reuse");
if (TraceMetadataChunkAllocation && Verbose) {
gclog_or_tty->print("SpaceManager::add_chunk: %d) ",
sum_count_in_chunks_in_use());
new_chunk->print_on(gclog_or_tty);
- vs_list()->chunk_manager()->locked_print_free_chunks(tty);
+ if (vs_list() != NULL) {
+ vs_list()->chunk_manager()->locked_print_free_chunks(tty);
+ }
}
}
@@ -2143,7 +2361,7 @@
// of memory if this returns null.
if (DumpSharedSpaces) {
assert(current_chunk() != NULL, "should never happen");
- inc_allocation_total(word_size);
+ inc_used_metrics(word_size);
return current_chunk()->allocate(word_size); // caller handles null result
}
if (current_chunk() != NULL) {
@@ -2154,7 +2372,7 @@
result = grow_and_allocate(word_size);
}
if (result > 0) {
- inc_allocation_total(word_size);
+ inc_used_metrics(word_size);
assert(result != (MetaWord*) chunks_in_use(MediumIndex),
"Head of the list is being allocated");
}
@@ -2188,20 +2406,14 @@
}
#ifdef ASSERT
-void SpaceManager::verify_allocation_total() {
+void SpaceManager::verify_allocated_blocks_words() {
// Verification is only guaranteed at a safepoint.
- if (SafepointSynchronize::is_at_safepoint()) {
- gclog_or_tty->print_cr("Chunk " PTR_FORMAT " allocation_total " SIZE_FORMAT
- " sum_used_in_chunks_in_use " SIZE_FORMAT,
- this,
- allocation_total(),
- sum_used_in_chunks_in_use());
- }
- MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
- assert(allocation_total() == sum_used_in_chunks_in_use(),
+ assert(SafepointSynchronize::is_at_safepoint() || !Universe::is_fully_initialized(),
+ "Verification can fail if the applications is running");
+ assert(allocated_blocks_words() == sum_used_in_chunks_in_use(),
err_msg("allocation total is not consistent " SIZE_FORMAT
" vs " SIZE_FORMAT,
- allocation_total(), sum_used_in_chunks_in_use()));
+ allocated_blocks_words(), sum_used_in_chunks_in_use()));
}
#endif
@@ -2257,14 +2469,65 @@
// MetaspaceAux
-size_t MetaspaceAux::used_in_bytes(Metaspace::MetadataType mdtype) {
+
+size_t MetaspaceAux::_allocated_capacity_words = 0;
+size_t MetaspaceAux::_allocated_used_words = 0;
+
+size_t MetaspaceAux::free_bytes() {
+ size_t result = 0;
+ if (Metaspace::class_space_list() != NULL) {
+ result = result + Metaspace::class_space_list()->free_bytes();
+ }
+ if (Metaspace::space_list() != NULL) {
+ result = result + Metaspace::space_list()->free_bytes();
+ }
+ return result;
+}
+
+void MetaspaceAux::dec_capacity(size_t words) {
+ assert_lock_strong(SpaceManager::expand_lock());
+ assert(words <= _allocated_capacity_words,
+ err_msg("About to decrement below 0: words " SIZE_FORMAT
+ " is greater than _allocated_capacity_words " SIZE_FORMAT,
+ words, _allocated_capacity_words));
+ _allocated_capacity_words = _allocated_capacity_words - words;
+}
+
+void MetaspaceAux::inc_capacity(size_t words) {
+ assert_lock_strong(SpaceManager::expand_lock());
+ // Needs to be atomic
+ _allocated_capacity_words = _allocated_capacity_words + words;
+}
+
+void MetaspaceAux::dec_used(size_t words) {
+ assert(words <= _allocated_used_words,
+ err_msg("About to decrement below 0: words " SIZE_FORMAT
+ " is greater than _allocated_used_words " SIZE_FORMAT,
+ words, _allocated_used_words));
+ // For CMS deallocation of the Metaspaces occurs during the
+ // sweep which is a concurrent phase. Protection by the expand_lock()
+ // is not enough since allocation is on a per Metaspace basis
+ // and protected by the Metaspace lock.
+ jlong minus_words = (jlong) - (jlong) words;
+ Atomic::add_ptr(minus_words, &_allocated_used_words);
+}
+
+void MetaspaceAux::inc_used(size_t words) {
+ // _allocated_used_words tracks allocations for
+ // each piece of metadata. Those allocations are
+ // generally done concurrently by different application
+ // threads so must be done atomically.
+ Atomic::add_ptr(words, &_allocated_used_words);
+}
+
+size_t MetaspaceAux::used_bytes_slow(Metaspace::MetadataType mdtype) {
size_t used = 0;
ClassLoaderDataGraphMetaspaceIterator iter;
while (iter.repeat()) {
Metaspace* msp = iter.get_next();
- // Sum allocation_total for each metaspace
+ // Sum allocated_blocks_words for each metaspace
if (msp != NULL) {
- used += msp->used_words(mdtype);
+ used += msp->used_words_slow(mdtype);
}
}
return used * BytesPerWord;
@@ -2282,13 +2545,15 @@
return free * BytesPerWord;
}
-size_t MetaspaceAux::capacity_in_bytes(Metaspace::MetadataType mdtype) {
- size_t capacity = free_chunks_total(mdtype);
+size_t MetaspaceAux::capacity_bytes_slow(Metaspace::MetadataType mdtype) {
+ // Don't count the space in the freelists. That space will be
+ // added to the capacity calculation as needed.
+ size_t capacity = 0;
ClassLoaderDataGraphMetaspaceIterator iter;
while (iter.repeat()) {
Metaspace* msp = iter.get_next();
if (msp != NULL) {
- capacity += msp->capacity_words(mdtype);
+ capacity += msp->capacity_words_slow(mdtype);
}
}
return capacity * BytesPerWord;
@@ -2315,23 +2580,30 @@
return free_chunks_total(mdtype) * BytesPerWord;
}
+size_t MetaspaceAux::free_chunks_total() {
+ return free_chunks_total(Metaspace::ClassType) +
+ free_chunks_total(Metaspace::NonClassType);
+}
+
+size_t MetaspaceAux::free_chunks_total_in_bytes() {
+ return free_chunks_total() * BytesPerWord;
+}
+
void MetaspaceAux::print_metaspace_change(size_t prev_metadata_used) {
gclog_or_tty->print(", [Metaspace:");
if (PrintGCDetails && Verbose) {
gclog_or_tty->print(" " SIZE_FORMAT
"->" SIZE_FORMAT
- "(" SIZE_FORMAT "/" SIZE_FORMAT ")",
+ "(" SIZE_FORMAT ")",
prev_metadata_used,
- used_in_bytes(),
- capacity_in_bytes(),
+ allocated_capacity_bytes(),
reserved_in_bytes());
} else {
gclog_or_tty->print(" " SIZE_FORMAT "K"
"->" SIZE_FORMAT "K"
- "(" SIZE_FORMAT "K/" SIZE_FORMAT "K)",
+ "(" SIZE_FORMAT "K)",
prev_metadata_used / K,
- used_in_bytes()/ K,
- capacity_in_bytes()/K,
+ allocated_capacity_bytes() / K,
reserved_in_bytes()/ K);
}
@@ -2346,23 +2618,30 @@
out->print_cr(" Metaspace total "
SIZE_FORMAT "K, used " SIZE_FORMAT "K,"
" reserved " SIZE_FORMAT "K",
- capacity_in_bytes()/K, used_in_bytes()/K, reserved_in_bytes()/K);
- out->print_cr(" data space "
- SIZE_FORMAT "K, used " SIZE_FORMAT "K,"
- " reserved " SIZE_FORMAT "K",
- capacity_in_bytes(nct)/K, used_in_bytes(nct)/K, reserved_in_bytes(nct)/K);
- out->print_cr(" class space "
- SIZE_FORMAT "K, used " SIZE_FORMAT "K,"
- " reserved " SIZE_FORMAT "K",
- capacity_in_bytes(ct)/K, used_in_bytes(ct)/K, reserved_in_bytes(ct)/K);
+ allocated_capacity_bytes()/K, allocated_used_bytes()/K, reserved_in_bytes()/K);
+#if 0
+// The calls to capacity_bytes_slow() and used_bytes_slow() cause
+// lock ordering assertion failures with some collectors. Do
+// not include this code until the lock ordering is fixed.
+ if (PrintGCDetails && Verbose) {
+ out->print_cr(" data space "
+ SIZE_FORMAT "K, used " SIZE_FORMAT "K,"
+ " reserved " SIZE_FORMAT "K",
+ capacity_bytes_slow(nct)/K, used_bytes_slow(nct)/K, reserved_in_bytes(nct)/K);
+ out->print_cr(" class space "
+ SIZE_FORMAT "K, used " SIZE_FORMAT "K,"
+ " reserved " SIZE_FORMAT "K",
+ capacity_bytes_slow(ct)/K, used_bytes_slow(ct)/K, reserved_in_bytes(ct)/K);
+ }
+#endif
}
// Print information for class space and data space separately.
// This is almost the same as above.
void MetaspaceAux::print_on(outputStream* out, Metaspace::MetadataType mdtype) {
size_t free_chunks_capacity_bytes = free_chunks_total_in_bytes(mdtype);
- size_t capacity_bytes = capacity_in_bytes(mdtype);
- size_t used_bytes = used_in_bytes(mdtype);
+ size_t capacity_bytes = capacity_bytes_slow(mdtype);
+ size_t used_bytes = used_bytes_slow(mdtype);
size_t free_bytes = free_in_bytes(mdtype);
size_t used_and_free = used_bytes + free_bytes +
free_chunks_capacity_bytes;
@@ -2435,6 +2714,36 @@
Metaspace::class_space_list()->chunk_manager()->verify();
}
+void MetaspaceAux::verify_capacity() {
+#ifdef ASSERT
+ size_t running_sum_capacity_bytes = allocated_capacity_bytes();
+ // For purposes of the running sum of used, verify against capacity
+ size_t capacity_in_use_bytes = capacity_bytes_slow();
+ assert(running_sum_capacity_bytes == capacity_in_use_bytes,
+ err_msg("allocated_capacity_words() * BytesPerWord " SIZE_FORMAT
+ " capacity_bytes_slow()" SIZE_FORMAT,
+ running_sum_capacity_bytes, capacity_in_use_bytes));
+#endif
+}
+
+void MetaspaceAux::verify_used() {
+#ifdef ASSERT
+ size_t running_sum_used_bytes = allocated_used_bytes();
+ // For purposes of the running sum of used, verify against capacity
+ size_t used_in_use_bytes = used_bytes_slow();
+ assert(allocated_used_bytes() == used_in_use_bytes,
+ err_msg("allocated_used_bytes() " SIZE_FORMAT
+ " used_bytes_slow()()" SIZE_FORMAT,
+ allocated_used_bytes(), used_in_use_bytes));
+#endif
+}
+
+void MetaspaceAux::verify_metrics() {
+ verify_capacity();
+ verify_used();
+}
+
+
// Metaspace methods
size_t Metaspace::_first_chunk_word_size = 0;
@@ -2584,8 +2893,8 @@
MetaWord* result;
MetaspaceGC::set_expand_after_GC(true);
size_t before_inc = MetaspaceGC::capacity_until_GC();
- size_t delta_words = MetaspaceGC::delta_capacity_until_GC(word_size);
- MetaspaceGC::inc_capacity_until_GC(delta_words);
+ size_t delta_bytes = MetaspaceGC::delta_capacity_until_GC(word_size) * BytesPerWord;
+ MetaspaceGC::inc_capacity_until_GC(delta_bytes);
if (PrintGCDetails && Verbose) {
gclog_or_tty->print_cr("Increase capacity to GC from " SIZE_FORMAT
" to " SIZE_FORMAT, before_inc, MetaspaceGC::capacity_until_GC());
@@ -2603,8 +2912,8 @@
return (char*)vsm()->current_chunk()->bottom();
}
-size_t Metaspace::used_words(MetadataType mdtype) const {
- // return vsm()->allocation_total();
+size_t Metaspace::used_words_slow(MetadataType mdtype) const {
+ // return vsm()->allocated_used_words();
return mdtype == ClassType ? class_vsm()->sum_used_in_chunks_in_use() :
vsm()->sum_used_in_chunks_in_use(); // includes overhead!
}
@@ -2619,16 +2928,24 @@
// have been made. Don't include space in the global freelist and
// in the space available in the dictionary which
// is already counted in some chunk.
-size_t Metaspace::capacity_words(MetadataType mdtype) const {
+size_t Metaspace::capacity_words_slow(MetadataType mdtype) const {
return mdtype == ClassType ? class_vsm()->sum_capacity_in_chunks_in_use() :
vsm()->sum_capacity_in_chunks_in_use();
}
+size_t Metaspace::used_bytes_slow(MetadataType mdtype) const {
+ return used_words_slow(mdtype) * BytesPerWord;
+}
+
+size_t Metaspace::capacity_bytes_slow(MetadataType mdtype) const {
+ return capacity_words_slow(mdtype) * BytesPerWord;
+}
+
void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) {
if (SafepointSynchronize::is_at_safepoint()) {
assert(Thread::current()->is_VM_thread(), "should be the VM thread");
// Don't take Heap_lock
- MutexLocker ml(vsm()->lock());
+ MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag);
if (word_size < TreeChunk<Metablock, FreeList>::min_size()) {
// Dark matter. Too small for dictionary.
#ifdef ASSERT
@@ -2642,7 +2959,7 @@
vsm()->deallocate(ptr, word_size);
}
} else {
- MutexLocker ml(vsm()->lock());
+ MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag);
if (word_size < TreeChunk<Metablock, FreeList>::min_size()) {
// Dark matter. Too small for dictionary.
@@ -2716,6 +3033,13 @@
return Metablock::initialize(result, word_size);
}
+void Metaspace::purge() {
+ MutexLockerEx cl(SpaceManager::expand_lock(),
+ Mutex::_no_safepoint_check_flag);
+ space_list()->purge();
+ class_space_list()->purge();
+}
+
void Metaspace::print_on(outputStream* out) const {
// Print both class virtual space counts and metaspace.
if (Verbose) {
@@ -2733,7 +3057,8 @@
// aren't deleted presently. When they are, some sort of locking might
// be needed. Note, locking this can cause inversion problems with the
// caller in MetaspaceObj::is_metadata() function.
- return space_list()->contains(ptr) || class_space_list()->contains(ptr);
+ return space_list()->contains(ptr) ||
+ class_space_list()->contains(ptr);
}
void Metaspace::verify() {
@@ -2742,10 +3067,6 @@
}
void Metaspace::dump(outputStream* const out) const {
- if (UseMallocOnly) {
- // Just print usage for now
- out->print_cr("usage %d", used_words(Metaspace::NonClassType));
- }
out->print_cr("\nVirtual space manager: " INTPTR_FORMAT, vsm());
vsm()->dump(out);
out->print_cr("\nClass space manager: " INTPTR_FORMAT, class_vsm());
--- a/hotspot/src/share/vm/memory/metaspace.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/metaspace.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -111,6 +111,10 @@
SpaceManager* _class_vsm;
SpaceManager* class_vsm() const { return _class_vsm; }
+ // Allocate space for metadata of type mdtype. This is space
+ // within a Metachunk and is used by
+ // allocate(ClassLoaderData*, size_t, bool, MetadataType, TRAPS)
+ // which returns a Metablock.
MetaWord* allocate(size_t word_size, MetadataType mdtype);
// Virtual Space lists for both classes and other metadata
@@ -133,11 +137,14 @@
static size_t first_class_chunk_word_size() { return _first_class_chunk_word_size; }
char* bottom() const;
- size_t used_words(MetadataType mdtype) const;
+ size_t used_words_slow(MetadataType mdtype) const;
size_t free_words(MetadataType mdtype) const;
- size_t capacity_words(MetadataType mdtype) const;
+ size_t capacity_words_slow(MetadataType mdtype) const;
size_t waste_words(MetadataType mdtype) const;
+ size_t used_bytes_slow(MetadataType mdtype) const;
+ size_t capacity_bytes_slow(MetadataType mdtype) const;
+
static Metablock* allocate(ClassLoaderData* loader_data, size_t size,
bool read_only, MetadataType mdtype, TRAPS);
void deallocate(MetaWord* ptr, size_t byte_size, bool is_class);
@@ -150,6 +157,9 @@
static bool contains(const void *ptr);
void dump(outputStream* const out) const;
+ // Free empty virtualspaces
+ static void purge();
+
void print_on(outputStream* st) const;
// Debugging support
void verify();
@@ -158,28 +168,81 @@
class MetaspaceAux : AllStatic {
// Statistics for class space and data space in metaspace.
- static size_t used_in_bytes(Metaspace::MetadataType mdtype);
+
+ // These methods iterate over the classloader data graph
+ // for the given Metaspace type. These are slow.
+ static size_t used_bytes_slow(Metaspace::MetadataType mdtype);
static size_t free_in_bytes(Metaspace::MetadataType mdtype);
- static size_t capacity_in_bytes(Metaspace::MetadataType mdtype);
+ static size_t capacity_bytes_slow(Metaspace::MetadataType mdtype);
+
+ // Iterates over the virtual space list.
static size_t reserved_in_bytes(Metaspace::MetadataType mdtype);
static size_t free_chunks_total(Metaspace::MetadataType mdtype);
static size_t free_chunks_total_in_bytes(Metaspace::MetadataType mdtype);
public:
- // Total of space allocated to metadata in all Metaspaces
- static size_t used_in_bytes() {
- return used_in_bytes(Metaspace::ClassType) +
- used_in_bytes(Metaspace::NonClassType);
+ // Running sum of space in all Metachunks that has been
+ // allocated to a Metaspace. This is used instead of
+ // iterating over all the classloaders
+ static size_t _allocated_capacity_words;
+ // Running sum of space in all Metachunks that have
+ // are being used for metadata.
+ static size_t _allocated_used_words;
+
+ public:
+ // Decrement and increment _allocated_capacity_words
+ static void dec_capacity(size_t words);
+ static void inc_capacity(size_t words);
+
+ // Decrement and increment _allocated_used_words
+ static void dec_used(size_t words);
+ static void inc_used(size_t words);
+
+ // Total of space allocated to metadata in all Metaspaces.
+ // This sums the space used in each Metachunk by
+ // iterating over the classloader data graph
+ static size_t used_bytes_slow() {
+ return used_bytes_slow(Metaspace::ClassType) +
+ used_bytes_slow(Metaspace::NonClassType);
}
- // Total of available space in all Metaspaces
- // Total of capacity allocated to all Metaspaces. This includes
- // space in Metachunks not yet allocated and in the Metachunk
- // freelist.
- static size_t capacity_in_bytes() {
- return capacity_in_bytes(Metaspace::ClassType) +
- capacity_in_bytes(Metaspace::NonClassType);
+ // Used by MetaspaceCounters
+ static size_t free_chunks_total();
+ static size_t free_chunks_total_in_bytes();
+
+ static size_t allocated_capacity_words() {
+ return _allocated_capacity_words;
+ }
+ static size_t allocated_capacity_bytes() {
+ return _allocated_capacity_words * BytesPerWord;
+ }
+
+ static size_t allocated_used_words() {
+ return _allocated_used_words;
+ }
+ static size_t allocated_used_bytes() {
+ return _allocated_used_words * BytesPerWord;
+ }
+
+ static size_t free_bytes();
+
+ // Total capacity in all Metaspaces
+ static size_t capacity_bytes_slow() {
+#ifdef PRODUCT
+ // Use allocated_capacity_bytes() in PRODUCT instead of this function.
+ guarantee(false, "Should not call capacity_bytes_slow() in the PRODUCT");
+#endif
+ size_t class_capacity = capacity_bytes_slow(Metaspace::ClassType);
+ size_t non_class_capacity = capacity_bytes_slow(Metaspace::NonClassType);
+ assert(allocated_capacity_bytes() == class_capacity + non_class_capacity,
+ err_msg("bad accounting: allocated_capacity_bytes() " SIZE_FORMAT
+ " class_capacity + non_class_capacity " SIZE_FORMAT
+ " class_capacity " SIZE_FORMAT " non_class_capacity " SIZE_FORMAT,
+ allocated_capacity_bytes(), class_capacity + non_class_capacity,
+ class_capacity, non_class_capacity));
+
+ return class_capacity + non_class_capacity;
}
// Total space reserved in all Metaspaces
@@ -198,6 +261,11 @@
static void print_waste(outputStream* out);
static void dump(outputStream* out);
static void verify_free_chunks();
+ // Checks that the values returned by allocated_capacity_bytes() and
+ // capacity_bytes_slow() are the same.
+ static void verify_capacity();
+ static void verify_used();
+ static void verify_metrics();
};
// Metaspace are deallocated when their class loader are GC'ed.
@@ -232,7 +300,6 @@
public:
static size_t capacity_until_GC() { return _capacity_until_GC; }
- static size_t capacity_until_GC_in_bytes() { return _capacity_until_GC * BytesPerWord; }
static void inc_capacity_until_GC(size_t v) { _capacity_until_GC += v; }
static void dec_capacity_until_GC(size_t v) {
_capacity_until_GC = _capacity_until_GC > v ? _capacity_until_GC - v : 0;
--- a/hotspot/src/share/vm/memory/metaspaceCounters.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/metaspaceCounters.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -29,6 +29,16 @@
MetaspaceCounters* MetaspaceCounters::_metaspace_counters = NULL;
+size_t MetaspaceCounters::calc_total_capacity() {
+ // The total capacity is the sum of
+ // 1) capacity of Metachunks in use by all Metaspaces
+ // 2) unused space at the end of each Metachunk
+ // 3) space in the freelist
+ size_t total_capacity = MetaspaceAux::allocated_capacity_bytes()
+ + MetaspaceAux::free_bytes() + MetaspaceAux::free_chunks_total_in_bytes();
+ return total_capacity;
+}
+
MetaspaceCounters::MetaspaceCounters() :
_capacity(NULL),
_used(NULL),
@@ -36,8 +46,8 @@
if (UsePerfData) {
size_t min_capacity = MetaspaceAux::min_chunk_size();
size_t max_capacity = MetaspaceAux::reserved_in_bytes();
- size_t curr_capacity = MetaspaceAux::capacity_in_bytes();
- size_t used = MetaspaceAux::used_in_bytes();
+ size_t curr_capacity = calc_total_capacity();
+ size_t used = MetaspaceAux::allocated_used_bytes();
initialize(min_capacity, max_capacity, curr_capacity, used);
}
@@ -82,15 +92,13 @@
void MetaspaceCounters::update_capacity() {
assert(UsePerfData, "Should not be called unless being used");
- assert(_capacity != NULL, "Should be initialized");
- size_t capacity_in_bytes = MetaspaceAux::capacity_in_bytes();
- _capacity->set_value(capacity_in_bytes);
+ size_t total_capacity = calc_total_capacity();
+ _capacity->set_value(total_capacity);
}
void MetaspaceCounters::update_used() {
assert(UsePerfData, "Should not be called unless being used");
- assert(_used != NULL, "Should be initialized");
- size_t used_in_bytes = MetaspaceAux::used_in_bytes();
+ size_t used_in_bytes = MetaspaceAux::allocated_used_bytes();
_used->set_value(used_in_bytes);
}
--- a/hotspot/src/share/vm/memory/metaspaceCounters.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/metaspaceCounters.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -37,6 +37,7 @@
size_t max_capacity,
size_t curr_capacity,
size_t used);
+ size_t calc_total_capacity();
public:
MetaspaceCounters();
~MetaspaceCounters();
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -376,18 +376,17 @@
const char* fmt = "%s space: %9d [ %4.1f%% of total] out of %9d bytes [%4.1f%% used] at " PTR_FORMAT;
Metaspace* ro_space = _loader_data->ro_metaspace();
Metaspace* rw_space = _loader_data->rw_metaspace();
- const size_t BPW = BytesPerWord;
// Allocated size of each space (may not be all occupied)
- const size_t ro_alloced = ro_space->capacity_words(Metaspace::NonClassType) * BPW;
- const size_t rw_alloced = rw_space->capacity_words(Metaspace::NonClassType) * BPW;
+ const size_t ro_alloced = ro_space->capacity_bytes_slow(Metaspace::NonClassType);
+ const size_t rw_alloced = rw_space->capacity_bytes_slow(Metaspace::NonClassType);
const size_t md_alloced = md_end-md_low;
const size_t mc_alloced = mc_end-mc_low;
const size_t total_alloced = ro_alloced + rw_alloced + md_alloced + mc_alloced;
// Occupied size of each space.
- const size_t ro_bytes = ro_space->used_words(Metaspace::NonClassType) * BPW;
- const size_t rw_bytes = rw_space->used_words(Metaspace::NonClassType) * BPW;
+ const size_t ro_bytes = ro_space->used_bytes_slow(Metaspace::NonClassType);
+ const size_t rw_bytes = rw_space->used_bytes_slow(Metaspace::NonClassType);
const size_t md_bytes = size_t(md_top - md_low);
const size_t mc_bytes = size_t(mc_top - mc_low);
--- a/hotspot/src/share/vm/memory/sharedHeap.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/sharedHeap.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -218,14 +218,13 @@
static AlwaysTrueClosure always_true;
void SharedHeap::process_weak_roots(OopClosure* root_closure,
- CodeBlobClosure* code_roots,
- OopClosure* non_root_closure) {
+ CodeBlobClosure* code_roots) {
// Global (weak) JNI handles
JNIHandles::weak_oops_do(&always_true, root_closure);
CodeCache::blobs_do(code_roots);
- StringTable::oops_do(root_closure);
- }
+ StringTable::oops_do(root_closure);
+}
void SharedHeap::set_barrier_set(BarrierSet* bs) {
_barrier_set = bs;
--- a/hotspot/src/share/vm/memory/sharedHeap.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/sharedHeap.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -249,8 +249,7 @@
// JNI weak roots, the code cache, system dictionary, symbol table,
// string table.
void process_weak_roots(OopClosure* root_closure,
- CodeBlobClosure* code_roots,
- OopClosure* non_root_closure);
+ CodeBlobClosure* code_roots);
// The functions below are helper functions that a subclass of
// "SharedHeap" can use in the implementation of its virtual
--- a/hotspot/src/share/vm/memory/universe.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/universe.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -1270,7 +1270,7 @@
st->print_cr("}");
}
-void Universe::verify(bool silent, VerifyOption option) {
+void Universe::verify(VerifyOption option, const char* prefix, bool silent) {
// The use of _verify_in_progress is a temporary work around for
// 6320749. Don't bother with a creating a class to set and clear
// it since it is only used in this method and the control flow is
@@ -1287,11 +1287,12 @@
HandleMark hm; // Handles created during verification can be zapped
_verify_count++;
+ if (!silent) gclog_or_tty->print(prefix);
if (!silent) gclog_or_tty->print("[Verifying ");
if (!silent) gclog_or_tty->print("threads ");
Threads::verify();
+ if (!silent) gclog_or_tty->print("heap ");
heap()->verify(silent, option);
-
if (!silent) gclog_or_tty->print("syms ");
SymbolTable::verify();
if (!silent) gclog_or_tty->print("strs ");
--- a/hotspot/src/share/vm/memory/universe.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/memory/universe.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -445,12 +445,12 @@
// Debugging
static bool verify_in_progress() { return _verify_in_progress; }
- static void verify(bool silent, VerifyOption option);
- static void verify(bool silent) {
- verify(silent, VerifyOption_Default /* option */);
+ static void verify(VerifyOption option, const char* prefix, bool silent = VerifySilently);
+ static void verify(const char* prefix, bool silent = VerifySilently) {
+ verify(VerifyOption_Default, prefix, silent);
}
- static void verify() {
- verify(false /* silent */);
+ static void verify(bool silent = VerifySilently) {
+ verify("", silent);
}
static int verify_count() { return _verify_count; }
--- a/hotspot/src/share/vm/oops/constantPool.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/oops/constantPool.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -40,6 +40,7 @@
#include "runtime/init.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/signature.hpp"
+#include "runtime/synchronizer.hpp"
#include "runtime/vframe.hpp"
ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) {
@@ -69,7 +70,6 @@
// only set to non-zero if constant pool is merged by RedefineClasses
set_version(0);
- set_lock(new Monitor(Monitor::nonleaf + 2, "A constant pool lock"));
// initialize tag array
int length = tags->length();
@@ -95,9 +95,6 @@
void ConstantPool::release_C_heap_structures() {
// walk constant pool and decrement symbol reference counts
unreference_symbols();
-
- delete _lock;
- set_lock(NULL);
}
objArrayOop ConstantPool::resolved_references() const {
@@ -154,9 +151,6 @@
ClassLoaderData* loader_data = pool_holder()->class_loader_data();
set_resolved_references(loader_data->add_handle(refs_handle));
}
-
- // Also need to recreate the mutex. Make sure this matches the constructor
- set_lock(new Monitor(Monitor::nonleaf + 2, "A constant pool lock"));
}
}
@@ -167,7 +161,23 @@
set_resolved_reference_length(
resolved_references() != NULL ? resolved_references()->length() : 0);
set_resolved_references(NULL);
- set_lock(NULL);
+}
+
+oop ConstantPool::lock() {
+ if (_pool_holder) {
+ // We re-use the _pool_holder's init_lock to reduce footprint.
+ // Notes on deadlocks:
+ // [1] This lock is a Java oop, so it can be recursively locked by
+ // the same thread without self-deadlocks.
+ // [2] Deadlock will happen if there is circular dependency between
+ // the <clinit> of two Java classes. However, in this case,
+ // the deadlock would have happened long before we reach
+ // ConstantPool::lock(), so reusing init_lock does not
+ // increase the possibility of deadlock.
+ return _pool_holder->init_lock();
+ } else {
+ return NULL;
+ }
}
int ConstantPool::cp_to_object_index(int cp_index) {
@@ -208,7 +218,9 @@
Symbol* name = NULL;
Handle loader;
- { MonitorLockerEx ml(this_oop->lock());
+ {
+ oop cplock = this_oop->lock();
+ ObjectLocker ol(cplock , THREAD, cplock != NULL);
if (this_oop->tag_at(which).is_unresolved_klass()) {
if (this_oop->tag_at(which).is_unresolved_klass_in_error()) {
@@ -255,7 +267,8 @@
bool throw_orig_error = false;
{
- MonitorLockerEx ml(this_oop->lock());
+ oop cplock = this_oop->lock();
+ ObjectLocker ol(cplock, THREAD, cplock != NULL);
// some other thread has beaten us and has resolved the class.
if (this_oop->tag_at(which).is_klass()) {
@@ -323,7 +336,8 @@
}
return k();
} else {
- MonitorLockerEx ml(this_oop->lock());
+ oop cplock = this_oop->lock();
+ ObjectLocker ol(cplock, THREAD, cplock != NULL);
// Only updated constant pool - if it is resolved.
do_resolve = this_oop->tag_at(which).is_unresolved_klass();
if (do_resolve) {
@@ -619,7 +633,8 @@
int tag, TRAPS) {
ResourceMark rm;
Symbol* error = PENDING_EXCEPTION->klass()->name();
- MonitorLockerEx ml(this_oop->lock()); // lock cpool to change tag.
+ oop cplock = this_oop->lock();
+ ObjectLocker ol(cplock, THREAD, cplock != NULL); // lock cpool to change tag.
int error_tag = (tag == JVM_CONSTANT_MethodHandle) ?
JVM_CONSTANT_MethodHandleInError : JVM_CONSTANT_MethodTypeInError;
@@ -780,7 +795,8 @@
if (cache_index >= 0) {
// Cache the oop here also.
Handle result_handle(THREAD, result_oop);
- MonitorLockerEx ml(this_oop->lock()); // don't know if we really need this
+ oop cplock = this_oop->lock();
+ ObjectLocker ol(cplock, THREAD, cplock != NULL); // don't know if we really need this
oop result = this_oop->resolved_references()->obj_at(cache_index);
// Benign race condition: resolved_references may already be filled in while we were trying to lock.
// The important thing here is that all threads pick up the same result.
@@ -1043,24 +1059,13 @@
case JVM_CONSTANT_InvokeDynamic:
{
- int k1 = invoke_dynamic_bootstrap_method_ref_index_at(index1);
- int k2 = cp2->invoke_dynamic_bootstrap_method_ref_index_at(index2);
- bool match = compare_entry_to(k1, cp2, k2, CHECK_false);
- if (!match) return false;
- k1 = invoke_dynamic_name_and_type_ref_index_at(index1);
- k2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2);
- match = compare_entry_to(k1, cp2, k2, CHECK_false);
- if (!match) return false;
- int argc = invoke_dynamic_argument_count_at(index1);
- if (argc == cp2->invoke_dynamic_argument_count_at(index2)) {
- for (int j = 0; j < argc; j++) {
- k1 = invoke_dynamic_argument_index_at(index1, j);
- k2 = cp2->invoke_dynamic_argument_index_at(index2, j);
- match = compare_entry_to(k1, cp2, k2, CHECK_false);
- if (!match) return false;
- }
- return true; // got through loop; all elements equal
- }
+ int k1 = invoke_dynamic_name_and_type_ref_index_at(index1);
+ int k2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2);
+ int i1 = invoke_dynamic_bootstrap_specifier_index(index1);
+ int i2 = cp2->invoke_dynamic_bootstrap_specifier_index(index2);
+ bool match = compare_entry_to(k1, cp2, k2, CHECK_false) &&
+ compare_operand_to(i1, cp2, i2, CHECK_false);
+ return match;
} break;
case JVM_CONSTANT_String:
@@ -1095,6 +1100,80 @@
} // end compare_entry_to()
+// Resize the operands array with delta_len and delta_size.
+// Used in RedefineClasses for CP merge.
+void ConstantPool::resize_operands(int delta_len, int delta_size, TRAPS) {
+ int old_len = operand_array_length(operands());
+ int new_len = old_len + delta_len;
+ int min_len = (delta_len > 0) ? old_len : new_len;
+
+ int old_size = operands()->length();
+ int new_size = old_size + delta_size;
+ int min_size = (delta_size > 0) ? old_size : new_size;
+
+ ClassLoaderData* loader_data = pool_holder()->class_loader_data();
+ Array<u2>* new_ops = MetadataFactory::new_array<u2>(loader_data, new_size, CHECK);
+
+ // Set index in the resized array for existing elements only
+ for (int idx = 0; idx < min_len; idx++) {
+ int offset = operand_offset_at(idx); // offset in original array
+ operand_offset_at_put(new_ops, idx, offset + 2*delta_len); // offset in resized array
+ }
+ // Copy the bootstrap specifiers only
+ Copy::conjoint_memory_atomic(operands()->adr_at(2*old_len),
+ new_ops->adr_at(2*new_len),
+ (min_size - 2*min_len) * sizeof(u2));
+ // Explicitly deallocate old operands array.
+ // Note, it is not needed for 7u backport.
+ if ( operands() != NULL) { // the safety check
+ MetadataFactory::free_array<u2>(loader_data, operands());
+ }
+ set_operands(new_ops);
+} // end resize_operands()
+
+
+// Extend the operands array with the length and size of the ext_cp operands.
+// Used in RedefineClasses for CP merge.
+void ConstantPool::extend_operands(constantPoolHandle ext_cp, TRAPS) {
+ int delta_len = operand_array_length(ext_cp->operands());
+ if (delta_len == 0) {
+ return; // nothing to do
+ }
+ int delta_size = ext_cp->operands()->length();
+
+ assert(delta_len > 0 && delta_size > 0, "extended operands array must be bigger");
+
+ if (operand_array_length(operands()) == 0) {
+ ClassLoaderData* loader_data = pool_holder()->class_loader_data();
+ Array<u2>* new_ops = MetadataFactory::new_array<u2>(loader_data, delta_size, CHECK);
+ // The first element index defines the offset of second part
+ operand_offset_at_put(new_ops, 0, 2*delta_len); // offset in new array
+ set_operands(new_ops);
+ } else {
+ resize_operands(delta_len, delta_size, CHECK);
+ }
+
+} // end extend_operands()
+
+
+// Shrink the operands array to a smaller array with new_len length.
+// Used in RedefineClasses for CP merge.
+void ConstantPool::shrink_operands(int new_len, TRAPS) {
+ int old_len = operand_array_length(operands());
+ if (new_len == old_len) {
+ return; // nothing to do
+ }
+ assert(new_len < old_len, "shrunken operands array must be smaller");
+
+ int free_base = operand_next_offset_at(new_len - 1);
+ int delta_len = new_len - old_len;
+ int delta_size = 2*delta_len + free_base - operands()->length();
+
+ resize_operands(delta_len, delta_size, CHECK);
+
+} // end shrink_operands()
+
+
void ConstantPool::copy_operands(constantPoolHandle from_cp,
constantPoolHandle to_cp,
TRAPS) {
@@ -1357,6 +1436,46 @@
} // end find_matching_entry()
+// Compare this constant pool's bootstrap specifier at idx1 to the constant pool
+// cp2's bootstrap specifier at idx2.
+bool ConstantPool::compare_operand_to(int idx1, constantPoolHandle cp2, int idx2, TRAPS) {
+ int k1 = operand_bootstrap_method_ref_index_at(idx1);
+ int k2 = cp2->operand_bootstrap_method_ref_index_at(idx2);
+ bool match = compare_entry_to(k1, cp2, k2, CHECK_false);
+
+ if (!match) {
+ return false;
+ }
+ int argc = operand_argument_count_at(idx1);
+ if (argc == cp2->operand_argument_count_at(idx2)) {
+ for (int j = 0; j < argc; j++) {
+ k1 = operand_argument_index_at(idx1, j);
+ k2 = cp2->operand_argument_index_at(idx2, j);
+ match = compare_entry_to(k1, cp2, k2, CHECK_false);
+ if (!match) {
+ return false;
+ }
+ }
+ return true; // got through loop; all elements equal
+ }
+ return false;
+} // end compare_operand_to()
+
+// Search constant pool search_cp for a bootstrap specifier that matches
+// this constant pool's bootstrap specifier at pattern_i index.
+// Return the index of a matching bootstrap specifier or (-1) if there is no match.
+int ConstantPool::find_matching_operand(int pattern_i,
+ constantPoolHandle search_cp, int search_len, TRAPS) {
+ for (int i = 0; i < search_len; i++) {
+ bool found = compare_operand_to(pattern_i, search_cp, i, CHECK_(-1));
+ if (found) {
+ return i;
+ }
+ }
+ return -1; // bootstrap specifier not found; return unused index (-1)
+} // end find_matching_operand()
+
+
#ifndef PRODUCT
const char* ConstantPool::printable_name_at(int which) {
--- a/hotspot/src/share/vm/oops/constantPool.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/oops/constantPool.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -111,7 +111,6 @@
int _version;
} _saved;
- Monitor* _lock;
void set_tags(Array<u1>* tags) { _tags = tags; }
void tag_at_put(int which, jbyte t) { tags()->at_put(which, t); }
@@ -567,6 +566,47 @@
_indy_argc_offset = 1, // u2 argc
_indy_argv_offset = 2 // u2 argv[argc]
};
+
+ // These functions are used in RedefineClasses for CP merge
+
+ int operand_offset_at(int bootstrap_specifier_index) {
+ assert(0 <= bootstrap_specifier_index &&
+ bootstrap_specifier_index < operand_array_length(operands()),
+ "Corrupted CP operands");
+ return operand_offset_at(operands(), bootstrap_specifier_index);
+ }
+ int operand_bootstrap_method_ref_index_at(int bootstrap_specifier_index) {
+ int offset = operand_offset_at(bootstrap_specifier_index);
+ return operands()->at(offset + _indy_bsm_offset);
+ }
+ int operand_argument_count_at(int bootstrap_specifier_index) {
+ int offset = operand_offset_at(bootstrap_specifier_index);
+ int argc = operands()->at(offset + _indy_argc_offset);
+ return argc;
+ }
+ int operand_argument_index_at(int bootstrap_specifier_index, int j) {
+ int offset = operand_offset_at(bootstrap_specifier_index);
+ return operands()->at(offset + _indy_argv_offset + j);
+ }
+ int operand_next_offset_at(int bootstrap_specifier_index) {
+ int offset = operand_offset_at(bootstrap_specifier_index) + _indy_argv_offset
+ + operand_argument_count_at(bootstrap_specifier_index);
+ return offset;
+ }
+ // Compare a bootsrap specifier in the operands arrays
+ bool compare_operand_to(int bootstrap_specifier_index1, constantPoolHandle cp2,
+ int bootstrap_specifier_index2, TRAPS);
+ // Find a bootsrap specifier in the operands array
+ int find_matching_operand(int bootstrap_specifier_index, constantPoolHandle search_cp,
+ int operands_cur_len, TRAPS);
+ // Resize the operands array with delta_len and delta_size
+ void resize_operands(int delta_len, int delta_size, TRAPS);
+ // Extend the operands array with the length and size of the ext_cp operands
+ void extend_operands(constantPoolHandle ext_cp, TRAPS);
+ // Shrink the operands array to a smaller array with new_len length
+ void shrink_operands(int new_len, TRAPS);
+
+
int invoke_dynamic_bootstrap_method_ref_index_at(int which) {
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
int op_base = invoke_dynamic_operand_base(which);
@@ -782,8 +822,17 @@
void set_resolved_reference_length(int length) { _saved._resolved_reference_length = length; }
int resolved_reference_length() const { return _saved._resolved_reference_length; }
- void set_lock(Monitor* lock) { _lock = lock; }
- Monitor* lock() { return _lock; }
+
+ // lock() may return null -- constant pool updates may happen before this lock is
+ // initialized, because the _pool_holder has not been fully initialized and
+ // has not been registered into the system dictionary. In this case, no other
+ // thread can be modifying this constantpool, so no synchronization is
+ // necessary.
+ //
+ // Use cplock() like this:
+ // oop cplock = cp->lock();
+ // ObjectLocker ol(cplock , THREAD, cplock != NULL);
+ oop lock();
// Decrease ref counts of symbols that are in the constant pool
// when the holder class is unloaded
--- a/hotspot/src/share/vm/oops/cpCache.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/oops/cpCache.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -266,7 +266,8 @@
// the lock, so that when the losing writer returns, he can use the linked
// cache entry.
- MonitorLockerEx ml(cpool->lock());
+ oop cplock = cpool->lock();
+ ObjectLocker ol(cplock, Thread::current(), cplock != NULL);
if (!is_f1_null()) {
return;
}
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -54,6 +54,7 @@
#include "runtime/javaCalls.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/thread.inline.hpp"
+#include "services/classLoadingService.hpp"
#include "services/threadService.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/macros.hpp"
@@ -418,25 +419,6 @@
set_annotations(NULL);
}
-volatile oop InstanceKlass::init_lock() const {
- volatile oop lock = _init_lock; // read once
- assert((oop)lock != NULL || !is_not_initialized(), // initialized or in_error state
- "only fully initialized state can have a null lock");
- return lock;
-}
-
-// Set the initialization lock to null so the object can be GC'ed. Any racing
-// threads to get this lock will see a null lock and will not lock.
-// That's okay because they all check for initialized state after getting
-// the lock and return.
-void InstanceKlass::fence_and_clear_init_lock() {
- // make sure previous stores are all done, notably the init_state.
- OrderAccess::storestore();
- klass_oop_store(&_init_lock, NULL);
- assert(!is_not_initialized(), "class must be initialized now");
-}
-
-
bool InstanceKlass::should_be_initialized() const {
return !is_initialized();
}
@@ -473,7 +455,7 @@
void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) {
EXCEPTION_MARK;
volatile oop init_lock = this_oop->init_lock();
- ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
+ ObjectLocker ol(init_lock, THREAD);
// abort if someone beat us to the initialization
if (!this_oop->is_not_initialized()) return; // note: not equivalent to is_initialized()
@@ -492,7 +474,6 @@
} else {
// linking successfull, mark class as initialized
this_oop->set_init_state (fully_initialized);
- this_oop->fence_and_clear_init_lock();
// trace
if (TraceClassInitialization) {
ResourceMark rm(THREAD);
@@ -619,7 +600,7 @@
// verification & rewriting
{
volatile oop init_lock = this_oop->init_lock();
- ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
+ ObjectLocker ol(init_lock, THREAD);
// rewritten will have been set if loader constraint error found
// on an earlier link attempt
// don't verify or rewrite if already rewritten
@@ -742,7 +723,7 @@
// Step 1
{
volatile oop init_lock = this_oop->init_lock();
- ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
+ ObjectLocker ol(init_lock, THREAD);
Thread *self = THREAD; // it's passed the current thread
@@ -890,9 +871,8 @@
void InstanceKlass::set_initialization_state_and_notify_impl(instanceKlassHandle this_oop, ClassState state, TRAPS) {
volatile oop init_lock = this_oop->init_lock();
- ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
+ ObjectLocker ol(init_lock, THREAD);
this_oop->set_init_state(state);
- this_oop->fence_and_clear_init_lock();
ol.notify_all(CHECK);
}
@@ -2312,7 +2292,29 @@
m->clear_all_breakpoints();
}
+
+void InstanceKlass::notify_unload_class(InstanceKlass* ik) {
+ // notify the debugger
+ if (JvmtiExport::should_post_class_unload()) {
+ JvmtiExport::post_class_unload(ik);
+ }
+
+ // notify ClassLoadingService of class unload
+ ClassLoadingService::notify_class_unloaded(ik);
+}
+
+void InstanceKlass::release_C_heap_structures(InstanceKlass* ik) {
+ // Clean up C heap
+ ik->release_C_heap_structures();
+ ik->constants()->release_C_heap_structures();
+}
+
void InstanceKlass::release_C_heap_structures() {
+
+ // Can't release the constant pool here because the constant pool can be
+ // deallocated separately from the InstanceKlass for default methods and
+ // redefine classes.
+
// Deallocate oop map cache
if (_oop_map_cache != NULL) {
delete _oop_map_cache;
@@ -2837,7 +2839,7 @@
st->print(BULLET"protection domain: "); ((InstanceKlass*)this)->protection_domain()->print_value_on(st); st->cr();
st->print(BULLET"host class: "); host_klass()->print_value_on_maybe_null(st); st->cr();
st->print(BULLET"signers: "); signers()->print_value_on(st); st->cr();
- st->print(BULLET"init_lock: "); ((oop)_init_lock)->print_value_on(st); st->cr();
+ st->print(BULLET"init_lock: "); ((oop)_init_lock)->print_value_on(st); st->cr();
if (source_file_name() != NULL) {
st->print(BULLET"source file: ");
source_file_name()->print_value_on(st);
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -184,8 +184,9 @@
oop _protection_domain;
// Class signers.
objArrayOop _signers;
- // Initialization lock. Must be one per class and it has to be a VM internal
- // object so java code cannot lock it (like the mirror)
+ // Lock for (1) initialization; (2) access to the ConstantPool of this class.
+ // Must be one per class and it has to be a VM internal object so java code
+ // cannot lock it (like the mirror).
// It has to be an object not a Mutex because it's held through java calls.
volatile oop _init_lock;
@@ -236,7 +237,7 @@
_misc_rewritten = 1 << 0, // methods rewritten.
_misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops
_misc_should_verify_class = 1 << 2, // allow caching of preverification
- _misc_is_anonymous = 1 << 3, // has embedded _inner_classes field
+ _misc_is_anonymous = 1 << 3, // has embedded _host_klass field
_misc_is_contended = 1 << 4, // marked with contended annotation
_misc_has_default_methods = 1 << 5 // class/superclass/implemented interfaces has default methods
};
@@ -934,7 +935,9 @@
// referenced by handles.
bool on_stack() const { return _constants->on_stack(); }
- void release_C_heap_structures();
+ // callbacks for actions during class unloading
+ static void notify_unload_class(InstanceKlass* ik);
+ static void release_C_heap_structures(InstanceKlass* ik);
// Parallel Scavenge and Parallel Old
PARALLEL_GC_DECLS
@@ -968,6 +971,7 @@
#endif // INCLUDE_ALL_GCS
u2 idnum_allocated_count() const { return _idnum_allocated_count; }
+
private:
// initialization state
#ifdef ASSERT
@@ -994,9 +998,10 @@
{ OrderAccess::release_store_ptr(&_methods_cached_itable_indices, indices); }
// Lock during initialization
- volatile oop init_lock() const;
- void set_init_lock(oop value) { klass_oop_store(&_init_lock, value); }
- void fence_and_clear_init_lock(); // after fully_initialized
+public:
+ volatile oop init_lock() const {return _init_lock; }
+private:
+ void set_init_lock(oop value) { klass_oop_store(&_init_lock, value); }
// Offsets for memory management
oop* adr_protection_domain() const { return (oop*)&this->_protection_domain;}
@@ -1022,6 +1027,8 @@
// Returns the array class with this class as element type
Klass* array_klass_impl(bool or_null, TRAPS);
+ // Free CHeap allocated fields.
+ void release_C_heap_structures();
public:
// CDS support - remove and restore oops from metadata. Oops are not shared.
virtual void remove_unshareable_info();
--- a/hotspot/src/share/vm/oops/klassVtable.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/oops/klassVtable.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -519,6 +519,9 @@
// check if a method is a miranda method, given a class's methods table and it's super
// the caller must make sure that the method belongs to an interface implemented by the class
bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* super) {
+ if (m->is_static()) {
+ return false;
+ }
Symbol* name = m->name();
Symbol* signature = m->signature();
if (InstanceKlass::find_method(class_methods, name, signature) == NULL) {
--- a/hotspot/src/share/vm/oops/method.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/oops/method.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -877,7 +877,7 @@
debug_only(No_Safepoint_Verifier nsv;)
nmethod *code = (nmethod *)OrderAccess::load_ptr_acquire(&_code);
if (code == NULL && UseCodeCacheFlushing) {
- nmethod *saved_code = CodeCache::find_and_remove_saved_code(this);
+ nmethod *saved_code = CodeCache::reanimate_saved_code(this);
if (saved_code != NULL) {
methodHandle method(this);
assert( ! saved_code->is_osr_method(), "should not get here for osr" );
--- a/hotspot/src/share/vm/oops/oop.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/oops/oop.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -103,11 +103,17 @@
// When String table needs to rehash
unsigned int oopDesc::new_hash(jint seed) {
+ EXCEPTION_MARK;
ResourceMark rm;
int length;
- jchar* chars = java_lang_String::as_unicode_string(this, length);
- // Use alternate hashing algorithm on the string
- return AltHashing::murmur3_32(seed, chars, length);
+ jchar* chars = java_lang_String::as_unicode_string(this, length, THREAD);
+ if (chars != NULL) {
+ // Use alternate hashing algorithm on the string
+ return AltHashing::murmur3_32(seed, chars, length);
+ } else {
+ vm_exit_out_of_memory(length, OOM_MALLOC_ERROR, "unable to create Unicode strings for String table rehash");
+ return 0;
+ }
}
VerifyOopClosure VerifyOopClosure::verify_oop;
--- a/hotspot/src/share/vm/opto/graphKit.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/opto/graphKit.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -3564,7 +3564,8 @@
Node* no_ctrl = NULL;
Node* no_base = __ top();
- Node* zero = __ ConI(0);
+ Node* zero = __ ConI(0);
+ Node* zeroX = __ ConX(0);
float likely = PROB_LIKELY(0.999);
float unlikely = PROB_UNLIKELY(0.999);
@@ -3590,7 +3591,9 @@
// if (!marking)
__ if_then(marking, BoolTest::ne, zero); {
- Node* index = __ load(__ ctrl(), index_adr, TypeInt::INT, T_INT, Compile::AliasIdxRaw);
+ BasicType index_bt = TypeX_X->basic_type();
+ assert(sizeof(size_t) == type2aelembytes(index_bt), "Loading G1 PtrQueue::_index with wrong size.");
+ Node* index = __ load(__ ctrl(), index_adr, TypeX_X, index_bt, Compile::AliasIdxRaw);
if (do_load) {
// load original value
@@ -3603,22 +3606,16 @@
Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw);
// is the queue for this thread full?
- __ if_then(index, BoolTest::ne, zero, likely); {
+ __ if_then(index, BoolTest::ne, zeroX, likely); {
// decrement the index
- Node* next_index = __ SubI(index, __ ConI(sizeof(intptr_t)));
- Node* next_indexX = next_index;
-#ifdef _LP64
- // We could refine the type for what it's worth
- // const TypeLong* lidxtype = TypeLong::make(CONST64(0), get_size_from_queue);
- next_indexX = _gvn.transform( new (C) ConvI2LNode(next_index, TypeLong::make(0, max_jlong, Type::WidenMax)) );
-#endif
+ Node* next_index = _gvn.transform(new (C) SubXNode(index, __ ConX(sizeof(intptr_t))));
// Now get the buffer location we will log the previous value into and store it
- Node *log_addr = __ AddP(no_base, buffer, next_indexX);
+ Node *log_addr = __ AddP(no_base, buffer, next_index);
__ store(__ ctrl(), log_addr, pre_val, T_OBJECT, Compile::AliasIdxRaw);
// update the index
- __ store(__ ctrl(), index_adr, next_index, T_INT, Compile::AliasIdxRaw);
+ __ store(__ ctrl(), index_adr, next_index, index_bt, Compile::AliasIdxRaw);
} __ else_(); {
@@ -3645,26 +3642,21 @@
Node* buffer,
const TypeFunc* tf) {
- Node* zero = __ ConI(0);
+ Node* zero = __ ConI(0);
+ Node* zeroX = __ ConX(0);
Node* no_base = __ top();
BasicType card_bt = T_BYTE;
// Smash zero into card. MUST BE ORDERED WRT TO STORE
__ storeCM(__ ctrl(), card_adr, zero, oop_store, oop_alias_idx, card_bt, Compile::AliasIdxRaw);
// Now do the queue work
- __ if_then(index, BoolTest::ne, zero); {
-
- Node* next_index = __ SubI(index, __ ConI(sizeof(intptr_t)));
- Node* next_indexX = next_index;
-#ifdef _LP64
- // We could refine the type for what it's worth
- // const TypeLong* lidxtype = TypeLong::make(CONST64(0), get_size_from_queue);
- next_indexX = _gvn.transform( new (C) ConvI2LNode(next_index, TypeLong::make(0, max_jlong, Type::WidenMax)) );
-#endif // _LP64
- Node* log_addr = __ AddP(no_base, buffer, next_indexX);
+ __ if_then(index, BoolTest::ne, zeroX); {
+
+ Node* next_index = _gvn.transform(new (C) SubXNode(index, __ ConX(sizeof(intptr_t))));
+ Node* log_addr = __ AddP(no_base, buffer, next_index);
__ store(__ ctrl(), log_addr, card_adr, T_ADDRESS, Compile::AliasIdxRaw);
- __ store(__ ctrl(), index_adr, next_index, T_INT, Compile::AliasIdxRaw);
+ __ store(__ ctrl(), index_adr, next_index, TypeX_X->basic_type(), Compile::AliasIdxRaw);
} __ else_(); {
__ make_leaf_call(tf, CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), "g1_wb_post", card_adr, __ thread());
@@ -3725,7 +3717,7 @@
// Now some values
// Use ctrl to avoid hoisting these values past a safepoint, which could
// potentially reset these fields in the JavaThread.
- Node* index = __ load(__ ctrl(), index_adr, TypeInt::INT, T_INT, Compile::AliasIdxRaw);
+ Node* index = __ load(__ ctrl(), index_adr, TypeX_X, TypeX_X->basic_type(), Compile::AliasIdxRaw);
Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw);
// Convert the store obj pointer to an int prior to doing math on it
--- a/hotspot/src/share/vm/opto/output.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/opto/output.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "asm/assembler.inline.hpp"
+#include "code/compiledIC.hpp"
#include "code/debugInfo.hpp"
#include "code/debugInfoRec.hpp"
#include "compiler/compileBroker.hpp"
@@ -41,8 +42,6 @@
#include "runtime/handles.inline.hpp"
#include "utilities/xmlstream.hpp"
-extern uint size_java_to_interp();
-extern uint reloc_java_to_interp();
extern uint size_exception_handler();
extern uint size_deopt_handler();
@@ -389,15 +388,15 @@
MachNode *mach = nj->as_Mach();
blk_size += (mach->alignment_required() - 1) * relocInfo::addr_unit(); // assume worst case padding
reloc_size += mach->reloc();
- if( mach->is_MachCall() ) {
+ if (mach->is_MachCall()) {
MachCallNode *mcall = mach->as_MachCall();
// This destination address is NOT PC-relative
mcall->method_set((intptr_t)mcall->entry_point());
- if( mcall->is_MachCallJava() && mcall->as_MachCallJava()->_method ) {
- stub_size += size_java_to_interp();
- reloc_size += reloc_java_to_interp();
+ if (mcall->is_MachCallJava() && mcall->as_MachCallJava()->_method) {
+ stub_size += CompiledStaticCall::to_interp_stub_size();
+ reloc_size += CompiledStaticCall::reloc_to_interp_stub();
}
} else if (mach->is_MachSafePoint()) {
// If call/safepoint are adjacent, account for possible
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -259,7 +259,8 @@
// bytes to the InstanceKlass here because they have not been
// validated and we're not at a safepoint.
constantPoolHandle constants(current_thread, ikh->constants());
- MonitorLockerEx ml(constants->lock()); // lock constant pool while we query it
+ oop cplock = constants->lock();
+ ObjectLocker ol(cplock, current_thread, cplock != NULL); // lock constant pool while we query it
JvmtiClassFileReconstituter reconstituter(ikh);
if (reconstituter.get_error() != JVMTI_ERROR_NONE) {
@@ -2417,7 +2418,8 @@
instanceKlassHandle ikh(thread, k_oop);
constantPoolHandle constants(thread, ikh->constants());
- MonitorLockerEx ml(constants->lock()); // lock constant pool while we query it
+ oop cplock = constants->lock();
+ ObjectLocker ol(cplock, thread, cplock != NULL); // lock constant pool while we query it
JvmtiConstantPoolReconstituter reconstituter(ikh);
if (reconstituter.get_error() != JVMTI_ERROR_NONE) {
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -415,20 +415,26 @@
// this is an indirect CP entry so it needs special handling
case JVM_CONSTANT_InvokeDynamic:
{
- // TBD: cross-checks and possible extra appends into CP and bsm operands
- // are needed as well. This issue is tracked by a separate bug 8007037.
- int bss_idx = scratch_cp->invoke_dynamic_bootstrap_specifier_index(scratch_i);
-
- int ref_i = scratch_cp->invoke_dynamic_name_and_type_ref_index_at(scratch_i);
- int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p,
+ // Index of the bootstrap specifier in the operands array
+ int old_bs_i = scratch_cp->invoke_dynamic_bootstrap_specifier_index(scratch_i);
+ int new_bs_i = find_or_append_operand(scratch_cp, old_bs_i, merge_cp_p,
+ merge_cp_length_p, THREAD);
+ // The bootstrap method NameAndType_info index
+ int old_ref_i = scratch_cp->invoke_dynamic_name_and_type_ref_index_at(scratch_i);
+ int new_ref_i = find_or_append_indirect_entry(scratch_cp, old_ref_i, merge_cp_p,
merge_cp_length_p, THREAD);
- if (new_ref_i != ref_i) {
+ if (new_bs_i != old_bs_i) {
RC_TRACE(0x00080000,
- ("InvokeDynamic entry@%d name_and_type ref_index change: %d to %d",
- *merge_cp_length_p, ref_i, new_ref_i));
+ ("InvokeDynamic entry@%d bootstrap_method_attr_index change: %d to %d",
+ *merge_cp_length_p, old_bs_i, new_bs_i));
}
-
- (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, bss_idx, new_ref_i);
+ if (new_ref_i != old_ref_i) {
+ RC_TRACE(0x00080000,
+ ("InvokeDynamic entry@%d name_and_type_index change: %d to %d",
+ *merge_cp_length_p, old_ref_i, new_ref_i));
+ }
+
+ (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, new_bs_i, new_ref_i);
if (scratch_i != *merge_cp_length_p) {
// The new entry in *merge_cp_p is at a different index than
// the new entry in scratch_cp so we need to map the index values.
@@ -492,6 +498,105 @@
} // end find_or_append_indirect_entry()
+// Append a bootstrap specifier into the merge_cp operands that is semantically equal
+// to the scratch_cp operands bootstrap specifier passed by the old_bs_i index.
+// Recursively append new merge_cp entries referenced by the new bootstrap specifier.
+void VM_RedefineClasses::append_operand(constantPoolHandle scratch_cp, int old_bs_i,
+ constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) {
+
+ int old_ref_i = scratch_cp->operand_bootstrap_method_ref_index_at(old_bs_i);
+ int new_ref_i = find_or_append_indirect_entry(scratch_cp, old_ref_i, merge_cp_p,
+ merge_cp_length_p, THREAD);
+ if (new_ref_i != old_ref_i) {
+ RC_TRACE(0x00080000,
+ ("operands entry@%d bootstrap method ref_index change: %d to %d",
+ _operands_cur_length, old_ref_i, new_ref_i));
+ }
+
+ Array<u2>* merge_ops = (*merge_cp_p)->operands();
+ int new_bs_i = _operands_cur_length;
+ // We have _operands_cur_length == 0 when the merge_cp operands is empty yet.
+ // However, the operand_offset_at(0) was set in the extend_operands() call.
+ int new_base = (new_bs_i == 0) ? (*merge_cp_p)->operand_offset_at(0)
+ : (*merge_cp_p)->operand_next_offset_at(new_bs_i - 1);
+ int argc = scratch_cp->operand_argument_count_at(old_bs_i);
+
+ ConstantPool::operand_offset_at_put(merge_ops, _operands_cur_length, new_base);
+ merge_ops->at_put(new_base++, new_ref_i);
+ merge_ops->at_put(new_base++, argc);
+
+ for (int i = 0; i < argc; i++) {
+ int old_arg_ref_i = scratch_cp->operand_argument_index_at(old_bs_i, i);
+ int new_arg_ref_i = find_or_append_indirect_entry(scratch_cp, old_arg_ref_i, merge_cp_p,
+ merge_cp_length_p, THREAD);
+ merge_ops->at_put(new_base++, new_arg_ref_i);
+ if (new_arg_ref_i != old_arg_ref_i) {
+ RC_TRACE(0x00080000,
+ ("operands entry@%d bootstrap method argument ref_index change: %d to %d",
+ _operands_cur_length, old_arg_ref_i, new_arg_ref_i));
+ }
+ }
+ if (old_bs_i != _operands_cur_length) {
+ // The bootstrap specifier in *merge_cp_p is at a different index than
+ // that in scratch_cp so we need to map the index values.
+ map_operand_index(old_bs_i, new_bs_i);
+ }
+ _operands_cur_length++;
+} // end append_operand()
+
+
+int VM_RedefineClasses::find_or_append_operand(constantPoolHandle scratch_cp,
+ int old_bs_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) {
+
+ int new_bs_i = old_bs_i; // bootstrap specifier index
+ bool match = (old_bs_i < _operands_cur_length) &&
+ scratch_cp->compare_operand_to(old_bs_i, *merge_cp_p, old_bs_i, THREAD);
+
+ if (!match) {
+ // forward reference in *merge_cp_p or not a direct match
+ int found_i = scratch_cp->find_matching_operand(old_bs_i, *merge_cp_p,
+ _operands_cur_length, THREAD);
+ if (found_i != -1) {
+ guarantee(found_i != old_bs_i, "compare_operand_to() and find_matching_operand() disagree");
+ // found a matching operand somewhere else in *merge_cp_p so just need a mapping
+ new_bs_i = found_i;
+ map_operand_index(old_bs_i, found_i);
+ } else {
+ // no match found so we have to append this bootstrap specifier to *merge_cp_p
+ append_operand(scratch_cp, old_bs_i, merge_cp_p, merge_cp_length_p, THREAD);
+ new_bs_i = _operands_cur_length - 1;
+ }
+ }
+ return new_bs_i;
+} // end find_or_append_operand()
+
+
+void VM_RedefineClasses::finalize_operands_merge(constantPoolHandle merge_cp, TRAPS) {
+ if (merge_cp->operands() == NULL) {
+ return;
+ }
+ // Shrink the merge_cp operands
+ merge_cp->shrink_operands(_operands_cur_length, CHECK);
+
+ if (RC_TRACE_ENABLED(0x00040000)) {
+ // don't want to loop unless we are tracing
+ int count = 0;
+ for (int i = 1; i < _operands_index_map_p->length(); i++) {
+ int value = _operands_index_map_p->at(i);
+ if (value != -1) {
+ RC_TRACE_WITH_THREAD(0x00040000, THREAD,
+ ("operands_index_map[%d]: old=%d new=%d", count, i, value));
+ count++;
+ }
+ }
+ }
+ // Clean-up
+ _operands_index_map_p = NULL;
+ _operands_cur_length = 0;
+ _operands_index_map_count = 0;
+} // end finalize_operands_merge()
+
+
jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
instanceKlassHandle the_class,
instanceKlassHandle scratch_class) {
@@ -765,6 +870,31 @@
} // end find_new_index()
+// Find new bootstrap specifier index value for old bootstrap specifier index
+// value by seaching the index map. Returns unused index (-1) if there is
+// no mapped value for the old bootstrap specifier index.
+int VM_RedefineClasses::find_new_operand_index(int old_index) {
+ if (_operands_index_map_count == 0) {
+ // map is empty so nothing can be found
+ return -1;
+ }
+
+ if (old_index == -1 || old_index >= _operands_index_map_p->length()) {
+ // The old_index is out of range so it is not mapped.
+ // This should not happen in regular constant pool merging use.
+ return -1;
+ }
+
+ int value = _operands_index_map_p->at(old_index);
+ if (value == -1) {
+ // the old_index is not mapped
+ return -1;
+ }
+
+ return value;
+} // end find_new_operand_index()
+
+
// Returns true if the current mismatch is due to a resolved/unresolved
// class pair. Otherwise, returns false.
bool VM_RedefineClasses::is_unresolved_class_mismatch(constantPoolHandle cp1,
@@ -1014,6 +1144,25 @@
} // end map_index()
+// Map old_index to new_index as needed.
+void VM_RedefineClasses::map_operand_index(int old_index, int new_index) {
+ if (find_new_operand_index(old_index) != -1) {
+ // old_index is already mapped
+ return;
+ }
+
+ if (old_index == new_index) {
+ // no mapping is needed
+ return;
+ }
+
+ _operands_index_map_p->at_put(old_index, new_index);
+ _operands_index_map_count++;
+
+ RC_TRACE(0x00040000, ("mapped bootstrap specifier at index %d to %d", old_index, new_index));
+} // end map_index()
+
+
// Merge old_cp and scratch_cp and return the results of the merge via
// merge_cp_p. The number of entries in *merge_cp_p is returned via
// merge_cp_length_p. The entries in old_cp occupy the same locations
@@ -1086,6 +1235,7 @@
} // end for each old_cp entry
ConstantPool::copy_operands(old_cp, *merge_cp_p, CHECK_0);
+ (*merge_cp_p)->extend_operands(scratch_cp, CHECK_0);
// We don't need to sanity check that *merge_cp_length_p is within
// *merge_cp_p bounds since we have the minimum on-entry check above.
@@ -1198,6 +1348,8 @@
CHECK_0);
}
+ finalize_operands_merge(*merge_cp_p, THREAD);
+
RC_TRACE_WITH_THREAD(0x00020000, THREAD,
("after pass 1b: merge_cp_len=%d, scratch_i=%d, index_map_len=%d",
*merge_cp_length_p, scratch_i, _index_map_count));
@@ -1270,6 +1422,11 @@
_index_map_count = 0;
_index_map_p = new intArray(scratch_cp->length(), -1);
+ _operands_cur_length = ConstantPool::operand_array_length(old_cp->operands());
+ _operands_index_map_count = 0;
+ _operands_index_map_p = new intArray(
+ ConstantPool::operand_array_length(scratch_cp->operands()), -1);
+
// reference to the cp holder is needed for copy_operands()
merge_cp->set_pool_holder(scratch_class());
bool result = merge_constant_pools(old_cp, scratch_cp, &merge_cp,
@@ -1400,7 +1557,6 @@
return true;
} // end rewrite_cp_refs()
-
// Rewrite constant pool references in the methods.
bool VM_RedefineClasses::rewrite_cp_refs_in_methods(
instanceKlassHandle scratch_class, TRAPS) {
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -359,8 +359,15 @@
// _index_map_p contains any entries.
int _index_map_count;
intArray * _index_map_p;
+
+ // _operands_index_map_count is just an optimization for knowing if
+ // _operands_index_map_p contains any entries.
+ int _operands_cur_length;
+ int _operands_index_map_count;
+ intArray * _operands_index_map_p;
+
// ptr to _class_count scratch_classes
- Klass** _scratch_classes;
+ Klass** _scratch_classes;
jvmtiError _res;
// Performance measurement support. These timers do not cover all
@@ -422,12 +429,19 @@
// Support for constant pool merging (these routines are in alpha order):
void append_entry(constantPoolHandle scratch_cp, int scratch_i,
constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
+ void append_operand(constantPoolHandle scratch_cp, int scratch_bootstrap_spec_index,
+ constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
+ void finalize_operands_merge(constantPoolHandle merge_cp, TRAPS);
int find_or_append_indirect_entry(constantPoolHandle scratch_cp, int scratch_i,
constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
+ int find_or_append_operand(constantPoolHandle scratch_cp, int scratch_bootstrap_spec_index,
+ constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
int find_new_index(int old_index);
+ int find_new_operand_index(int old_bootstrap_spec_index);
bool is_unresolved_class_mismatch(constantPoolHandle cp1, int index1,
constantPoolHandle cp2, int index2);
void map_index(constantPoolHandle scratch_cp, int old_index, int new_index);
+ void map_operand_index(int old_bootstrap_spec_index, int new_bootstrap_spec_index);
bool merge_constant_pools(constantPoolHandle old_cp,
constantPoolHandle scratch_cp, constantPoolHandle *merge_cp_p,
int *merge_cp_length_p, TRAPS);
--- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -153,7 +153,8 @@
size_t s = initial_size * sizeof(JvmtiTagHashmapEntry*);
_table = (JvmtiTagHashmapEntry**)os::malloc(s, mtInternal);
if (_table == NULL) {
- vm_exit_out_of_memory(s, "unable to allocate initial hashtable for jvmti object tags");
+ vm_exit_out_of_memory(s, OOM_MALLOC_ERROR,
+ "unable to allocate initial hashtable for jvmti object tags");
}
for (int i=0; i<initial_size; i++) {
_table[i] = NULL;
--- a/hotspot/src/share/vm/prims/methodHandles.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -67,7 +67,8 @@
TraceTime timer("MethodHandles adapters generation", TraceStartupTime);
_adapter_code = MethodHandlesAdapterBlob::create(adapter_code_size);
if (_adapter_code == NULL)
- vm_exit_out_of_memory(adapter_code_size, "CodeCache: no room for MethodHandles adapters");
+ vm_exit_out_of_memory(adapter_code_size, OOM_MALLOC_ERROR,
+ "CodeCache: no room for MethodHandles adapters");
{
CodeBuffer code(_adapter_code);
MethodHandlesAdapterGenerator g(&code);
--- a/hotspot/src/share/vm/prims/whitebox.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/prims/whitebox.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -310,12 +310,8 @@
WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString))
ResourceMark rm(THREAD);
int len;
- jchar* name = java_lang_String::as_unicode_string(JNIHandles::resolve(javaString), len);
- oop found_string = StringTable::the_table()->lookup(name, len);
- if (found_string == NULL) {
- return false;
- }
- return true;
+ jchar* name = java_lang_String::as_unicode_string(JNIHandles::resolve(javaString), len, CHECK_false);
+ return (StringTable::lookup(name, len) != NULL);
WB_END
@@ -324,6 +320,11 @@
Universe::heap()->collect(GCCause::_last_ditch_collection);
WB_END
+
+WB_ENTRY(jlong, WB_ReserveMemory(JNIEnv* env, jobject o, jlong size))
+ return (jlong)os::reserve_memory(size, NULL, 0);
+WB_END
+
//Some convenience methods to deal with objects from java
int WhiteBox::offset_for_field(const char* field_name, oop object,
Symbol* signature_symbol) {
@@ -425,6 +426,8 @@
CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState},
{CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable },
{CC"fullGC", CC"()V", (void*)&WB_FullGC },
+
+ {CC"reserveMemory", CC"(J)J", (void*)&WB_ReserveMemory },
};
#undef CC
@@ -436,9 +439,29 @@
instanceKlassHandle ikh = instanceKlassHandle(JNIHandles::resolve(wbclass)->klass());
Handle loader(ikh->class_loader());
if (loader.is_null()) {
+ ResourceMark rm;
ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
- jint result = env->RegisterNatives(wbclass, methods, sizeof(methods)/sizeof(methods[0]));
- if (result == 0) {
+ bool result = true;
+ // one by one registration natives for exception catching
+ jclass exceptionKlass = env->FindClass(vmSymbols::java_lang_NoSuchMethodError()->as_C_string());
+ for (int i = 0, n = sizeof(methods) / sizeof(methods[0]); i < n; ++i) {
+ if (env->RegisterNatives(wbclass, methods + i, 1) != 0) {
+ result = false;
+ if (env->ExceptionCheck() && env->IsInstanceOf(env->ExceptionOccurred(), exceptionKlass)) {
+ // j.l.NoSuchMethodError is thrown when a method can't be found or a method is not native
+ // ignoring the exception
+ tty->print_cr("Warning: 'NoSuchMethodError' on register of sun.hotspot.WhiteBox::%s%s", methods[i].name, methods[i].signature);
+ env->ExceptionClear();
+ } else {
+ // register is failed w/o exception or w/ unexpected exception
+ tty->print_cr("Warning: unexpected error on register of sun.hotspot.WhiteBox::%s%s. All methods will be unregistered", methods[i].name, methods[i].signature);
+ env->UnregisterNatives(wbclass);
+ break;
+ }
+ }
+ }
+
+ if (result) {
WhiteBox::set_used();
}
}
--- a/hotspot/src/share/vm/runtime/arguments.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -2224,6 +2224,55 @@
return JNI_OK;
}
+// Checks if name in command-line argument -agent{lib,path}:name[=options]
+// represents a valid HPROF of JDWP agent. is_path==true denotes that we
+// are dealing with -agentpath (case where name is a path), otherwise with
+// -agentlib
+bool valid_hprof_or_jdwp_agent(char *name, bool is_path) {
+ char *_name;
+ const char *_hprof = "hprof", *_jdwp = "jdwp";
+ size_t _len_hprof, _len_jdwp, _len_prefix;
+
+ if (is_path) {
+ if ((_name = strrchr(name, (int) *os::file_separator())) == NULL) {
+ return false;
+ }
+
+ _name++; // skip past last path separator
+ _len_prefix = strlen(JNI_LIB_PREFIX);
+
+ if (strncmp(_name, JNI_LIB_PREFIX, _len_prefix) != 0) {
+ return false;
+ }
+
+ _name += _len_prefix;
+ _len_hprof = strlen(_hprof);
+ _len_jdwp = strlen(_jdwp);
+
+ if (strncmp(_name, _hprof, _len_hprof) == 0) {
+ _name += _len_hprof;
+ }
+ else if (strncmp(_name, _jdwp, _len_jdwp) == 0) {
+ _name += _len_jdwp;
+ }
+ else {
+ return false;
+ }
+
+ if (strcmp(_name, JNI_LIB_SUFFIX) != 0) {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (strcmp(name, _hprof) == 0 || strcmp(name, _jdwp) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args,
SysClassPath* scp_p,
bool* scp_assembly_required_p,
@@ -2322,7 +2371,7 @@
options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(pos + 1) + 1, mtInternal), pos + 1);
}
#if !INCLUDE_JVMTI
- if ((strcmp(name, "hprof") == 0) || (strcmp(name, "jdwp") == 0)) {
+ if (valid_hprof_or_jdwp_agent(name, is_absolute_path)) {
jio_fprintf(defaultStream::error_stream(),
"Profiling and debugging agents are not supported in this VM\n");
return JNI_ERR;
--- a/hotspot/src/share/vm/runtime/compilationPolicy.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/compilationPolicy.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -109,6 +109,9 @@
// Returns true if m is allowed to be compiled
bool CompilationPolicy::can_be_compiled(methodHandle m, int comp_level) {
+ // allow any levels for WhiteBox
+ assert(WhiteBoxAPI || comp_level == CompLevel_all || is_compile(comp_level), "illegal compilation level");
+
if (m->is_abstract()) return false;
if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false;
@@ -122,7 +125,13 @@
return false;
}
if (comp_level == CompLevel_all) {
- return !m->is_not_compilable(CompLevel_simple) && !m->is_not_compilable(CompLevel_full_optimization);
+ if (TieredCompilation) {
+ // enough to be compilable at any level for tiered
+ return !m->is_not_compilable(CompLevel_simple) || !m->is_not_compilable(CompLevel_full_optimization);
+ } else {
+ // must be compilable at available level for non-tiered
+ return !m->is_not_compilable(CompLevel_highest_tier);
+ }
} else if (is_compile(comp_level)) {
return !m->is_not_compilable(comp_level);
}
@@ -436,7 +445,7 @@
reset_counter_for_invocation_event(m);
const char* comment = "count";
- if (is_compilation_enabled() && can_be_compiled(m)) {
+ if (is_compilation_enabled() && can_be_compiled(m, comp_level)) {
nmethod* nm = m->code();
if (nm == NULL ) {
CompileBroker::compile_method(m, InvocationEntryBci, comp_level, m, hot_count, comment, thread);
@@ -449,7 +458,7 @@
const int hot_count = m->backedge_count();
const char* comment = "backedge_count";
- if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m)) {
+ if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m, comp_level)) {
CompileBroker::compile_method(m, bci, comp_level, m, hot_count, comment, thread);
NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));)
}
@@ -467,7 +476,7 @@
reset_counter_for_invocation_event(m);
const char* comment = "count";
- if (is_compilation_enabled() && m->code() == NULL && can_be_compiled(m)) {
+ if (is_compilation_enabled() && m->code() == NULL && can_be_compiled(m, comp_level)) {
ResourceMark rm(thread);
frame fr = thread->last_frame();
assert(fr.is_interpreted_frame(), "must be interpreted");
@@ -505,7 +514,7 @@
const int hot_count = m->backedge_count();
const char* comment = "backedge_count";
- if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m)) {
+ if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m, comp_level)) {
CompileBroker::compile_method(m, bci, comp_level, m, hot_count, comment, thread);
NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));)
}
@@ -600,7 +609,7 @@
// If the caller method is too big or something then we do not want to
// compile it just to inline a method
- if (!can_be_compiled(next_m)) {
+ if (!can_be_compiled(next_m, CompLevel_any)) {
msg = "caller cannot be compiled";
break;
}
--- a/hotspot/src/share/vm/runtime/globals.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -2123,6 +2123,9 @@
product(intx, PrefetchFieldsAhead, -1, \
"How many fields ahead to prefetch in oop scan (<= 0 means off)") \
\
+ diagnostic(bool, VerifySilently, false, \
+ "Don't print print the verification progress") \
+ \
diagnostic(bool, VerifyDuringStartup, false, \
"Verify memory system before executing any Java code " \
"during VM initialization") \
@@ -3179,6 +3182,9 @@
product(uintx, CodeCacheFlushingMinimumFreeSpace, 1500*K, \
"When less than X space left, start code cache cleaning") \
\
+ product(uintx, CodeCacheFlushingFraction, 2, \
+ "Fraction of the code cache that is flushed when full") \
+ \
/* interpreter debugging */ \
develop(intx, BinarySwitchThreshold, 5, \
"Minimal number of lookupswitch entries for rewriting to binary " \
@@ -3223,8 +3229,9 @@
develop(bool, ReplayCompiles, false, \
"Enable replay of compilations from ReplayDataFile") \
\
- develop(ccstr, ReplayDataFile, "replay.txt", \
- "file containing compilation replay information") \
+ product(ccstr, ReplayDataFile, NULL, \
+ "File containing compilation replay information" \
+ "[default: ./replay_pid%p.log] (%p replaced with pid)") \
\
develop(intx, ReplaySuppressInitializers, 2, \
"Controls handling of class initialization during replay" \
@@ -3237,8 +3244,8 @@
develop(bool, ReplayIgnoreInitErrors, false, \
"Ignore exceptions thrown during initialization for replay") \
\
- develop(bool, DumpReplayDataOnError, true, \
- "record replay data for crashing compiler threads") \
+ product(bool, DumpReplayDataOnError, true, \
+ "Record replay data for crashing compiler threads") \
\
product(bool, CICompilerCountPerCPU, false, \
"1 compiler thread for log(N CPUs)") \
@@ -3247,7 +3254,9 @@
"Fire OutOfMemoryErrors throughout CI for testing the compiler " \
"(non-negative value throws OOM after this many CI accesses " \
"in each compile)") \
- \
+ notproduct(intx, CICrashAt, -1, \
+ "id of compilation to trigger assert in compiler thread for " \
+ "the purpose of testing, e.g. generation of replay data") \
notproduct(bool, CIObjectFactoryVerify, false, \
"enable potentially expensive verification in ciObjectFactory") \
\
--- a/hotspot/src/share/vm/runtime/objectMonitor.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -2404,7 +2404,7 @@
size_t sz = strlen (SyncKnobs) ;
char * knobs = (char *) malloc (sz + 2) ;
if (knobs == NULL) {
- vm_exit_out_of_memory (sz + 2, "Parse SyncKnobs") ;
+ vm_exit_out_of_memory (sz + 2, OOM_MALLOC_ERROR, "Parse SyncKnobs") ;
guarantee (0, "invariant") ;
}
strcpy (knobs, SyncKnobs) ;
--- a/hotspot/src/share/vm/runtime/os.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -454,6 +454,7 @@
// File i/o operations
static const int default_file_open_flags();
static int open(const char *path, int oflag, int mode);
+ static FILE* open(int fd, const char* mode);
static int close(int fd);
static jlong lseek(int fd, jlong offset, int whence);
static char* native_path(char *path);
@@ -477,7 +478,7 @@
static const char* dll_file_extension();
static const char* get_temp_directory();
- static const char* get_current_directory(char *buf, int buflen);
+ static const char* get_current_directory(char *buf, size_t buflen);
// Builds a platform-specific full library path given a ld path and lib name
// Returns true if buffer contains full path to existing file, false otherwise
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -1316,12 +1316,6 @@
assert(stub_frame.is_runtime_frame(), "sanity check");
frame caller_frame = stub_frame.sender(®_map);
- // MethodHandle invokes don't have a CompiledIC and should always
- // simply redispatch to the callee_target.
- address sender_pc = caller_frame.pc();
- CodeBlob* sender_cb = caller_frame.cb();
- nmethod* sender_nm = sender_cb->as_nmethod_or_null();
-
if (caller_frame.is_interpreted_frame() ||
caller_frame.is_entry_frame()) {
Method* callee = thread->callee_target();
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -154,9 +154,10 @@
// Set carry flags on the counters if necessary
void SimpleThresholdPolicy::handle_counter_overflow(Method* method) {
MethodCounters *mcs = method->method_counters();
- assert(mcs != NULL, "");
- set_carry_if_necessary(mcs->invocation_counter());
- set_carry_if_necessary(mcs->backedge_counter());
+ if (mcs != NULL) {
+ set_carry_if_necessary(mcs->invocation_counter());
+ set_carry_if_necessary(mcs->backedge_counter());
+ }
MethodData* mdo = method->method_data();
if (mdo != NULL) {
set_carry_if_necessary(mdo->invocation_counter());
--- a/hotspot/src/share/vm/runtime/stubRoutines.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -147,7 +147,7 @@
TraceTime timer("StubRoutines generation 1", TraceStartupTime);
_code1 = BufferBlob::create("StubRoutines (1)", code_size1);
if (_code1 == NULL) {
- vm_exit_out_of_memory(code_size1, "CodeCache: no room for StubRoutines (1)");
+ vm_exit_out_of_memory(code_size1, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (1)");
}
CodeBuffer buffer(_code1);
StubGenerator_generate(&buffer, false);
@@ -199,7 +199,7 @@
TraceTime timer("StubRoutines generation 2", TraceStartupTime);
_code2 = BufferBlob::create("StubRoutines (2)", code_size2);
if (_code2 == NULL) {
- vm_exit_out_of_memory(code_size2, "CodeCache: no room for StubRoutines (2)");
+ vm_exit_out_of_memory(code_size2, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (2)");
}
CodeBuffer buffer(_code2);
StubGenerator_generate(&buffer, true);
--- a/hotspot/src/share/vm/runtime/sweeper.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/sweeper.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -136,13 +136,12 @@
jint NMethodSweeper::_locked_seen = 0;
jint NMethodSweeper::_not_entrant_seen_on_stack = 0;
-bool NMethodSweeper::_rescan = false;
-bool NMethodSweeper::_do_sweep = false;
-bool NMethodSweeper::_was_full = false;
-jint NMethodSweeper::_advise_to_sweep = 0;
-jlong NMethodSweeper::_last_was_full = 0;
-uint NMethodSweeper::_highest_marked = 0;
-long NMethodSweeper::_was_full_traversal = 0;
+bool NMethodSweeper::_resweep = false;
+jint NMethodSweeper::_flush_token = 0;
+jlong NMethodSweeper::_last_full_flush_time = 0;
+int NMethodSweeper::_highest_marked = 0;
+int NMethodSweeper::_dead_compile_ids = 0;
+long NMethodSweeper::_last_flush_traversal_id = 0;
class MarkActivationClosure: public CodeBlobClosure {
public:
@@ -155,20 +154,16 @@
};
static MarkActivationClosure mark_activation_closure;
+bool NMethodSweeper::sweep_in_progress() {
+ return (_current != NULL);
+}
+
void NMethodSweeper::scan_stacks() {
assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint");
if (!MethodFlushing) return;
- _do_sweep = true;
// No need to synchronize access, since this is always executed at a
- // safepoint. If we aren't in the middle of scan and a rescan
- // hasn't been requested then just return. If UseCodeCacheFlushing is on and
- // code cache flushing is in progress, don't skip sweeping to help make progress
- // clearing space in the code cache.
- if ((_current == NULL && !_rescan) && !(UseCodeCacheFlushing && !CompileBroker::should_compile_new_jobs())) {
- _do_sweep = false;
- return;
- }
+ // safepoint.
// Make sure CompiledIC_lock in unlocked, since we might update some
// inline caches. If it is, we just bail-out and try later.
@@ -176,7 +171,7 @@
// Check for restart
assert(CodeCache::find_blob_unsafe(_current) == _current, "Sweeper nmethod cached state invalid");
- if (_current == NULL) {
+ if (!sweep_in_progress() && _resweep) {
_seen = 0;
_invocations = NmethodSweepFraction;
_current = CodeCache::first_nmethod();
@@ -187,39 +182,30 @@
Threads::nmethods_do(&mark_activation_closure);
// reset the flags since we started a scan from the beginning.
- _rescan = false;
+ _resweep = false;
_locked_seen = 0;
_not_entrant_seen_on_stack = 0;
}
if (UseCodeCacheFlushing) {
- if (!CodeCache::needs_flushing()) {
- // scan_stacks() runs during a safepoint, no race with setters
- _advise_to_sweep = 0;
+ // only allow new flushes after the interval is complete.
+ jlong now = os::javaTimeMillis();
+ jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000;
+ jlong curr_interval = now - _last_full_flush_time;
+ if (curr_interval > max_interval) {
+ _flush_token = 0;
}
- if (was_full()) {
- // There was some progress so attempt to restart the compiler
- jlong now = os::javaTimeMillis();
- jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000;
- jlong curr_interval = now - _last_was_full;
- if ((!CodeCache::needs_flushing()) && (curr_interval > max_interval)) {
- CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation);
- set_was_full(false);
-
- // Update the _last_was_full time so we can tell how fast the
- // code cache is filling up
- _last_was_full = os::javaTimeMillis();
-
- log_sweep("restart_compiler");
- }
+ if (!CodeCache::needs_flushing() && !CompileBroker::should_compile_new_jobs()) {
+ CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation);
+ log_sweep("restart_compiler");
}
}
}
void NMethodSweeper::possibly_sweep() {
assert(JavaThread::current()->thread_state() == _thread_in_vm, "must run in vm mode");
- if ((!MethodFlushing) || (!_do_sweep)) return;
+ if (!MethodFlushing || !sweep_in_progress()) return;
if (_invocations > 0) {
// Only one thread at a time will sweep
@@ -253,6 +239,14 @@
tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_nmethods(), _invocations);
}
+ if (!CompileBroker::should_compile_new_jobs()) {
+ // If we have turned off compilations we might as well do full sweeps
+ // in order to reach the clean state faster. Otherwise the sleeping compiler
+ // threads will slow down sweeping. After a few iterations the cache
+ // will be clean and sweeping stops (_resweep will not be set)
+ _invocations = 1;
+ }
+
// We want to visit all nmethods after NmethodSweepFraction
// invocations so divide the remaining number of nmethods by the
// remaining number of invocations. This is only an estimate since
@@ -296,7 +290,7 @@
assert(_invocations > 1 || _current == NULL, "must have scanned the whole cache");
- if (_current == NULL && !_rescan && (_locked_seen || _not_entrant_seen_on_stack)) {
+ if (!sweep_in_progress() && !_resweep && (_locked_seen || _not_entrant_seen_on_stack)) {
// we've completed a scan without making progress but there were
// nmethods we were unable to process either because they were
// locked or were still on stack. We don't have to aggresively
@@ -318,6 +312,13 @@
if (_invocations == 1) {
log_sweep("finished");
}
+
+ // Sweeper is the only case where memory is released,
+ // check here if it is time to restart the compiler.
+ if (UseCodeCacheFlushing && !CompileBroker::should_compile_new_jobs() && !CodeCache::needs_flushing()) {
+ CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation);
+ log_sweep("restart_compiler");
+ }
}
class NMethodMarker: public StackObj {
@@ -392,7 +393,7 @@
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm);
}
nm->mark_for_reclamation();
- _rescan = true;
+ _resweep = true;
SWEEP(nm);
}
} else if (nm->is_not_entrant()) {
@@ -403,7 +404,7 @@
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm);
}
nm->make_zombie();
- _rescan = true;
+ _resweep = true;
SWEEP(nm);
} else {
// Still alive, clean up its inline caches
@@ -425,16 +426,15 @@
release_nmethod(nm);
} else {
nm->make_zombie();
- _rescan = true;
+ _resweep = true;
SWEEP(nm);
}
} else {
assert(nm->is_alive(), "should be alive");
if (UseCodeCacheFlushing) {
- if ((nm->method()->code() != nm) && !(nm->is_locked_by_vm()) && !(nm->is_osr_method()) &&
- (_traversals > _was_full_traversal+2) && (((uint)nm->compile_id()) < _highest_marked) &&
- CodeCache::needs_flushing()) {
+ if (nm->is_speculatively_disconnected() && !nm->is_locked_by_vm() && !nm->is_osr_method() &&
+ (_traversals > _last_flush_traversal_id + 2) && (nm->compile_id() < _highest_marked)) {
// This method has not been called since the forced cleanup happened
nm->make_not_entrant();
}
@@ -457,41 +457,27 @@
// _code field is restored and the Method*/nmethod
// go back to their normal state.
void NMethodSweeper::handle_full_code_cache(bool is_full) {
- // Only the first one to notice can advise us to start early cleaning
- if (!is_full){
- jint old = Atomic::cmpxchg( 1, &_advise_to_sweep, 0 );
- if (old != 0) {
- return;
- }
- }
if (is_full) {
// Since code cache is full, immediately stop new compiles
- bool did_set = CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation);
- if (!did_set) {
- // only the first to notice can start the cleaning,
- // others will go back and block
- return;
+ if (CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation)) {
+ log_sweep("disable_compiler");
}
- set_was_full(true);
+ }
- // If we run out within MinCodeCacheFlushingInterval of the last unload time, give up
- jlong now = os::javaTimeMillis();
- jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000;
- jlong curr_interval = now - _last_was_full;
- if (curr_interval < max_interval) {
- _rescan = true;
- log_sweep("disable_compiler", "flushing_interval='" UINT64_FORMAT "'",
- curr_interval/1000);
- return;
- }
+ // Make sure only one thread can flush
+ // The token is reset after CodeCacheMinimumFlushInterval in scan stacks,
+ // no need to check the timeout here.
+ jint old = Atomic::cmpxchg( 1, &_flush_token, 0 );
+ if (old != 0) {
+ return;
}
VM_HandleFullCodeCache op(is_full);
VMThread::execute(&op);
- // rescan again as soon as possible
- _rescan = true;
+ // resweep again as soon as possible
+ _resweep = true;
}
void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) {
@@ -500,62 +486,64 @@
debug_only(jlong start = os::javaTimeMillis();)
- if ((!was_full()) && (is_full)) {
- if (!CodeCache::needs_flushing()) {
- log_sweep("restart_compiler");
- CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation);
- return;
- }
- }
+ // Traverse the code cache trying to dump the oldest nmethods
+ int curr_max_comp_id = CompileBroker::get_compilation_id();
+ int flush_target = ((curr_max_comp_id - _dead_compile_ids) / CodeCacheFlushingFraction) + _dead_compile_ids;
- // Traverse the code cache trying to dump the oldest nmethods
- uint curr_max_comp_id = CompileBroker::get_compilation_id();
- uint flush_target = ((curr_max_comp_id - _highest_marked) >> 1) + _highest_marked;
log_sweep("start_cleaning");
nmethod* nm = CodeCache::alive_nmethod(CodeCache::first());
jint disconnected = 0;
jint made_not_entrant = 0;
+ jint nmethod_count = 0;
+
while ((nm != NULL)){
- uint curr_comp_id = nm->compile_id();
+ int curr_comp_id = nm->compile_id();
// OSR methods cannot be flushed like this. Also, don't flush native methods
// since they are part of the JDK in most cases
- if (nm->is_in_use() && (!nm->is_osr_method()) && (!nm->is_locked_by_vm()) &&
- (!nm->is_native_method()) && ((curr_comp_id < flush_target))) {
+ if (!nm->is_osr_method() && !nm->is_locked_by_vm() && !nm->is_native_method()) {
+
+ // only count methods that can be speculatively disconnected
+ nmethod_count++;
- if ((nm->method()->code() == nm)) {
- // This method has not been previously considered for
- // unloading or it was restored already
- CodeCache::speculatively_disconnect(nm);
- disconnected++;
- } else if (nm->is_speculatively_disconnected()) {
- // This method was previously considered for preemptive unloading and was not called since then
- CompilationPolicy::policy()->delay_compilation(nm->method());
- nm->make_not_entrant();
- made_not_entrant++;
- }
+ if (nm->is_in_use() && (curr_comp_id < flush_target)) {
+ if ((nm->method()->code() == nm)) {
+ // This method has not been previously considered for
+ // unloading or it was restored already
+ CodeCache::speculatively_disconnect(nm);
+ disconnected++;
+ } else if (nm->is_speculatively_disconnected()) {
+ // This method was previously considered for preemptive unloading and was not called since then
+ CompilationPolicy::policy()->delay_compilation(nm->method());
+ nm->make_not_entrant();
+ made_not_entrant++;
+ }
- if (curr_comp_id > _highest_marked) {
- _highest_marked = curr_comp_id;
+ if (curr_comp_id > _highest_marked) {
+ _highest_marked = curr_comp_id;
+ }
}
}
nm = CodeCache::alive_nmethod(CodeCache::next(nm));
}
+ // remember how many compile_ids wheren't seen last flush.
+ _dead_compile_ids = curr_max_comp_id - nmethod_count;
+
log_sweep("stop_cleaning",
"disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "'",
disconnected, made_not_entrant);
// Shut off compiler. Sweeper will start over with a new stack scan and
// traversal cycle and turn it back on if it clears enough space.
- if (was_full()) {
- _last_was_full = os::javaTimeMillis();
- CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation);
+ if (is_full) {
+ _last_full_flush_time = os::javaTimeMillis();
}
// After two more traversals the sweeper will get rid of unrestored nmethods
- _was_full_traversal = _traversals;
+ _last_flush_traversal_id = _traversals;
+ _resweep = true;
#ifdef ASSERT
jlong end = os::javaTimeMillis();
if(PrintMethodFlushing && Verbose) {
--- a/hotspot/src/share/vm/runtime/sweeper.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/sweeper.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -35,26 +35,29 @@
static nmethod* _current; // Current nmethod
static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache
- static volatile int _invocations; // No. of invocations left until we are completed with this pass
- static volatile int _sweep_started; // Flag to control conc sweeper
+ static volatile int _invocations; // No. of invocations left until we are completed with this pass
+ static volatile int _sweep_started; // Flag to control conc sweeper
- static bool _rescan; // Indicates that we should do a full rescan of the
- // of the code cache looking for work to do.
- static bool _do_sweep; // Flag to skip the conc sweep if no stack scan happened
- static int _locked_seen; // Number of locked nmethods encountered during the scan
+ //The following are reset in scan_stacks and synchronized by the safepoint
+ static bool _resweep; // Indicates that a change has happend and we want another sweep,
+ // always checked and reset at a safepoint so memory will be in sync.
+ static int _locked_seen; // Number of locked nmethods encountered during the scan
static int _not_entrant_seen_on_stack; // Number of not entrant nmethod were are still on stack
+ static jint _flush_token; // token that guards method flushing, making sure it is executed only once.
- static bool _was_full; // remember if we did emergency unloading
- static jint _advise_to_sweep; // flag to indicate code cache getting full
- static jlong _last_was_full; // timestamp of last emergency unloading
- static uint _highest_marked; // highest compile id dumped at last emergency unloading
- static long _was_full_traversal; // trav number at last emergency unloading
+ // These are set during a flush, a VM-operation
+ static long _last_flush_traversal_id; // trav number at last flush unloading
+ static jlong _last_full_flush_time; // timestamp of last emergency unloading
+
+ // These are synchronized by the _sweep_started token
+ static int _highest_marked; // highest compile id dumped at last emergency unloading
+ static int _dead_compile_ids; // number of compile ids that where not in the cache last flush
static void process_nmethod(nmethod *nm);
-
static void release_nmethod(nmethod* nm);
static void log_sweep(const char* msg, const char* format = NULL, ...);
+ static bool sweep_in_progress();
public:
static long traversal_count() { return _traversals; }
@@ -71,17 +74,14 @@
static void possibly_sweep(); // Compiler threads call this to sweep
static void notify(nmethod* nm) {
- // Perform a full scan of the code cache from the beginning. No
+ // Request a new sweep of the code cache from the beginning. No
// need to synchronize the setting of this flag since it only
// changes to false at safepoint so we can never overwrite it with false.
- _rescan = true;
+ _resweep = true;
}
static void handle_full_code_cache(bool is_full); // Called by compilers who fail to allocate
static void speculative_disconnect_nmethods(bool was_full); // Called by vm op to deal with alloc failure
-
- static void set_was_full(bool state) { _was_full = state; }
- static bool was_full() { return _was_full; }
};
#endif // SHARE_VM_RUNTIME_SWEEPER_HPP
--- a/hotspot/src/share/vm/runtime/synchronizer.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/synchronizer.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -1018,7 +1018,8 @@
// We might be able to induce a STW safepoint and scavenge enough
// objectMonitors to permit progress.
if (temp == NULL) {
- vm_exit_out_of_memory (sizeof (ObjectMonitor[_BLOCKSIZE]), "Allocate ObjectMonitors") ;
+ vm_exit_out_of_memory (sizeof (ObjectMonitor[_BLOCKSIZE]), OOM_MALLOC_ERROR,
+ "Allocate ObjectMonitors");
}
// Format the block.
--- a/hotspot/src/share/vm/runtime/thread.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/thread.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -3447,7 +3447,8 @@
assert (Universe::is_fully_initialized(), "not initialized");
if (VerifyDuringStartup) {
- VM_Verify verify_op(false /* silent */); // make sure we're starting with a clean slate
+ // Make sure we're starting with a clean slate.
+ VM_Verify verify_op;
VMThread::execute(&verify_op);
}
--- a/hotspot/src/share/vm/runtime/virtualspace.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/virtualspace.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -60,72 +60,6 @@
initialize(size, alignment, large, NULL, 0, executable);
}
-char *
-ReservedSpace::align_reserved_region(char* addr, const size_t len,
- const size_t prefix_size,
- const size_t prefix_align,
- const size_t suffix_size,
- const size_t suffix_align)
-{
- assert(addr != NULL, "sanity");
- const size_t required_size = prefix_size + suffix_size;
- assert(len >= required_size, "len too small");
-
- const size_t s = size_t(addr);
- const size_t beg_ofs = (s + prefix_size) & (suffix_align - 1);
- const size_t beg_delta = beg_ofs == 0 ? 0 : suffix_align - beg_ofs;
-
- if (len < beg_delta + required_size) {
- return NULL; // Cannot do proper alignment.
- }
- const size_t end_delta = len - (beg_delta + required_size);
-
- if (beg_delta != 0) {
- os::release_memory(addr, beg_delta);
- }
-
- if (end_delta != 0) {
- char* release_addr = (char*) (s + beg_delta + required_size);
- os::release_memory(release_addr, end_delta);
- }
-
- return (char*) (s + beg_delta);
-}
-
-char* ReservedSpace::reserve_and_align(const size_t reserve_size,
- const size_t prefix_size,
- const size_t prefix_align,
- const size_t suffix_size,
- const size_t suffix_align)
-{
- assert(reserve_size > prefix_size + suffix_size, "should not be here");
-
- char* raw_addr = os::reserve_memory(reserve_size, NULL, prefix_align);
- if (raw_addr == NULL) return NULL;
-
- char* result = align_reserved_region(raw_addr, reserve_size, prefix_size,
- prefix_align, suffix_size,
- suffix_align);
- if (result == NULL && !os::release_memory(raw_addr, reserve_size)) {
- fatal("os::release_memory failed");
- }
-
-#ifdef ASSERT
- if (result != NULL) {
- const size_t raw = size_t(raw_addr);
- const size_t res = size_t(result);
- assert(res >= raw, "alignment decreased start addr");
- assert(res + prefix_size + suffix_size <= raw + reserve_size,
- "alignment increased end addr");
- assert((res & (prefix_align - 1)) == 0, "bad alignment of prefix");
- assert(((res + prefix_size) & (suffix_align - 1)) == 0,
- "bad alignment of suffix");
- }
-#endif
-
- return result;
-}
-
// Helper method.
static bool failed_to_reserve_as_requested(char* base, char* requested_address,
const size_t size, bool special)
@@ -155,92 +89,6 @@
return true;
}
-ReservedSpace::ReservedSpace(const size_t suffix_size,
- const size_t suffix_align,
- char* requested_address,
- const size_t noaccess_prefix)
-{
- assert(suffix_size != 0, "sanity");
- assert(suffix_align != 0, "sanity");
- assert((suffix_size & (suffix_align - 1)) == 0,
- "suffix_size not divisible by suffix_align");
-
- // Assert that if noaccess_prefix is used, it is the same as prefix_align.
- // Add in noaccess_prefix to prefix
- const size_t adjusted_prefix_size = noaccess_prefix;
- const size_t size = adjusted_prefix_size + suffix_size;
-
- // On systems where the entire region has to be reserved and committed up
- // front, the compound alignment normally done by this method is unnecessary.
- const bool try_reserve_special = UseLargePages &&
- suffix_align == os::large_page_size();
- if (!os::can_commit_large_page_memory() && try_reserve_special) {
- initialize(size, suffix_align, true, requested_address, noaccess_prefix,
- false);
- return;
- }
-
- _base = NULL;
- _size = 0;
- _alignment = 0;
- _special = false;
- _noaccess_prefix = 0;
- _executable = false;
-
- // Optimistically try to reserve the exact size needed.
- char* addr;
- if (requested_address != 0) {
- requested_address -= noaccess_prefix; // adjust address
- assert(requested_address != NULL, "huge noaccess prefix?");
- addr = os::attempt_reserve_memory_at(size, requested_address);
- if (failed_to_reserve_as_requested(addr, requested_address, size, false)) {
- // OS ignored requested address. Try different address.
- addr = NULL;
- }
- } else {
- addr = os::reserve_memory(size, NULL, suffix_align);
- }
- if (addr == NULL) return;
-
- // Check whether the result has the needed alignment
- const size_t ofs = (size_t(addr) + adjusted_prefix_size) & (suffix_align - 1);
- if (ofs != 0) {
- // Wrong alignment. Release, allocate more space and do manual alignment.
- //
- // On most operating systems, another allocation with a somewhat larger size
- // will return an address "close to" that of the previous allocation. The
- // result is often the same address (if the kernel hands out virtual
- // addresses from low to high), or an address that is offset by the increase
- // in size. Exploit that to minimize the amount of extra space requested.
- if (!os::release_memory(addr, size)) {
- fatal("os::release_memory failed");
- }
-
- const size_t extra = MAX2(ofs, suffix_align - ofs);
- addr = reserve_and_align(size + extra, adjusted_prefix_size, suffix_align,
- suffix_size, suffix_align);
- if (addr == NULL) {
- // Try an even larger region. If this fails, address space is exhausted.
- addr = reserve_and_align(size + suffix_align, adjusted_prefix_size,
- suffix_align, suffix_size, suffix_align);
- }
-
- if (requested_address != 0 &&
- failed_to_reserve_as_requested(addr, requested_address, size, false)) {
- // As a result of the alignment constraints, the allocated addr differs
- // from the requested address. Return back to the caller who can
- // take remedial action (like try again without a requested address).
- assert(_base == NULL, "should be");
- return;
- }
- }
-
- _base = addr;
- _size = size;
- _alignment = suffix_align;
- _noaccess_prefix = noaccess_prefix;
-}
-
void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
char* requested_address,
const size_t noaccess_prefix,
@@ -476,20 +324,6 @@
protect_noaccess_prefix(size);
}
-ReservedHeapSpace::ReservedHeapSpace(const size_t heap_space_size,
- const size_t alignment,
- char* requested_address) :
- ReservedSpace(heap_space_size, alignment,
- requested_address,
- (UseCompressedOops && (Universe::narrow_oop_base() != NULL) &&
- Universe::narrow_oop_use_implicit_null_checks()) ?
- lcm(os::vm_page_size(), alignment) : 0) {
- if (base() > 0) {
- MemTracker::record_virtual_memory_type((address)base(), mtJavaHeap);
- }
- protect_noaccess_prefix(heap_space_size);
-}
-
// Reserve space for code segment. Same as Java heap only we mark this as
// executable.
ReservedCodeSpace::ReservedCodeSpace(size_t r_size,
--- a/hotspot/src/share/vm/runtime/virtualspace.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/virtualspace.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -47,28 +47,6 @@
const size_t noaccess_prefix,
bool executable);
- // Release parts of an already-reserved memory region [addr, addr + len) to
- // get a new region that has "compound alignment." Return the start of the
- // resulting region, or NULL on failure.
- //
- // The region is logically divided into a prefix and a suffix. The prefix
- // starts at the result address, which is aligned to prefix_align. The suffix
- // starts at result address + prefix_size, which is aligned to suffix_align.
- // The total size of the result region is size prefix_size + suffix_size.
- char* align_reserved_region(char* addr, const size_t len,
- const size_t prefix_size,
- const size_t prefix_align,
- const size_t suffix_size,
- const size_t suffix_align);
-
- // Reserve memory, call align_reserved_region() to alignment it and return the
- // result.
- char* reserve_and_align(const size_t reserve_size,
- const size_t prefix_size,
- const size_t prefix_align,
- const size_t suffix_size,
- const size_t suffix_align);
-
protected:
// Create protection page at the beginning of the space.
void protect_noaccess_prefix(const size_t size);
@@ -79,9 +57,6 @@
ReservedSpace(size_t size, size_t alignment, bool large,
char* requested_address = NULL,
const size_t noaccess_prefix = 0);
- ReservedSpace(const size_t suffix_size, const size_t suffix_align,
- char* requested_address,
- const size_t noaccess_prefix = 0);
ReservedSpace(size_t size, size_t alignment, bool large, bool executable);
// Accessors
@@ -128,8 +103,6 @@
// Constructor
ReservedHeapSpace(size_t size, size_t forced_base_alignment,
bool large, char* requested_address);
- ReservedHeapSpace(const size_t prefix_size, const size_t prefix_align,
- char* requested_address);
};
// Class encapsulating behavior specific memory space for Code
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -828,6 +828,7 @@
nonstatic_field(nmethod, _lock_count, jint) \
nonstatic_field(nmethod, _stack_traversal_mark, long) \
nonstatic_field(nmethod, _compile_id, int) \
+ nonstatic_field(nmethod, _comp_level, int) \
nonstatic_field(nmethod, _exception_cache, ExceptionCache*) \
nonstatic_field(nmethod, _marked_for_deoptimization, bool) \
\
--- a/hotspot/src/share/vm/runtime/vmThread.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/vmThread.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -293,7 +293,7 @@
os::check_heap();
// Silent verification so as not to pollute normal output,
// unless we really asked for it.
- Universe::verify(!(PrintGCDetails || Verbose));
+ Universe::verify(!(PrintGCDetails || Verbose) || VerifySilently);
}
CompileBroker::set_should_block();
--- a/hotspot/src/share/vm/runtime/vm_operations.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/runtime/vm_operations.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -302,7 +302,7 @@
private:
bool _silent;
public:
- VM_Verify(bool silent) : _silent(silent) {}
+ VM_Verify(bool silent = VerifySilently) : _silent(silent) {}
VMOp_Type type() const { return VMOp_Verify; }
void doit();
};
--- a/hotspot/src/share/vm/services/memBaseline.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/services/memBaseline.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,9 +23,12 @@
*/
#include "precompiled.hpp"
#include "memory/allocation.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/thread.inline.hpp"
#include "services/memBaseline.hpp"
#include "services/memTracker.hpp"
+
MemType2Name MemBaseline::MemType2NameMap[NUMBER_OF_MEMORY_TYPE] = {
{mtJavaHeap, "Java Heap"},
{mtClass, "Class"},
@@ -149,6 +152,15 @@
return true;
}
+// check if there is a safepoint in progress, if so, block the thread
+// for the safepoint
+void MemBaseline::check_safepoint(JavaThread* thr) {
+ if (SafepointSynchronize::is_synchronizing()) {
+ // grab and drop the SR_lock to honor the safepoint protocol
+ MutexLocker ml(thr->SR_lock());
+ }
+}
+
// baseline mmap'd memory records, generate overall summary and summaries by
// memory types
bool MemBaseline::baseline_vm_summary(const MemPointerArray* vm_records) {
@@ -306,7 +318,7 @@
committed_rec->pc() != vm_ptr->pc()) {
if (!_vm_map->append(vm_ptr)) {
return false;
- }
+ }
committed_rec = (VMMemRegionEx*)_vm_map->at(_vm_map->length() - 1);
} else {
committed_rec->expand_region(vm_ptr->addr(), vm_ptr->size());
@@ -344,16 +356,27 @@
// baseline a snapshot. If summary_only = false, memory usages aggregated by
// callsites are also baselined.
+// The method call can be lengthy, especially when detail tracking info is
+// requested. So the method checks for safepoint explicitly.
bool MemBaseline::baseline(MemSnapshot& snapshot, bool summary_only) {
- MutexLockerEx snapshot_locker(snapshot._lock, true);
+ Thread* THREAD = Thread::current();
+ assert(THREAD->is_Java_thread(), "must be a JavaThread");
+ MutexLocker snapshot_locker(snapshot._lock);
reset();
- _baselined = baseline_malloc_summary(snapshot._alloc_ptrs) &&
- baseline_vm_summary(snapshot._vm_ptrs);
+ _baselined = baseline_malloc_summary(snapshot._alloc_ptrs);
+ if (_baselined) {
+ check_safepoint((JavaThread*)THREAD);
+ _baselined = baseline_vm_summary(snapshot._vm_ptrs);
+ }
_number_of_classes = snapshot.number_of_classes();
if (!summary_only && MemTracker::track_callsite() && _baselined) {
- _baselined = baseline_malloc_details(snapshot._alloc_ptrs) &&
- baseline_vm_details(snapshot._vm_ptrs);
+ check_safepoint((JavaThread*)THREAD);
+ _baselined = baseline_malloc_details(snapshot._alloc_ptrs);
+ if (_baselined) {
+ check_safepoint((JavaThread*)THREAD);
+ _baselined = baseline_vm_details(snapshot._vm_ptrs);
+ }
}
return _baselined;
}
--- a/hotspot/src/share/vm/services/memBaseline.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/services/memBaseline.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -330,6 +330,9 @@
// should not use copy constructor
MemBaseline(MemBaseline& copy) { ShouldNotReachHere(); }
+ // check and block at a safepoint
+ static inline void check_safepoint(JavaThread* thr);
+
public:
// create a memory baseline
MemBaseline();
--- a/hotspot/src/share/vm/services/memTracker.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/services/memTracker.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -573,7 +573,7 @@
// baseline current memory snapshot
bool MemTracker::baseline() {
- MutexLockerEx lock(_query_lock, true);
+ MutexLocker lock(_query_lock);
MemSnapshot* snapshot = get_snapshot();
if (snapshot != NULL) {
return _baseline.baseline(*snapshot, false);
@@ -584,7 +584,7 @@
// print memory usage from current snapshot
bool MemTracker::print_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only) {
MemBaseline baseline;
- MutexLockerEx lock(_query_lock, true);
+ MutexLocker lock(_query_lock);
MemSnapshot* snapshot = get_snapshot();
if (snapshot != NULL && baseline.baseline(*snapshot, summary_only)) {
BaselineReporter reporter(out, unit);
@@ -597,7 +597,7 @@
// Whitebox API for blocking until the current generation of NMT data has been merged
bool MemTracker::wbtest_wait_for_data_merge() {
// NMT can't be shutdown while we're holding _query_lock
- MutexLockerEx lock(_query_lock, true);
+ MutexLocker lock(_query_lock);
assert(_worker_thread != NULL, "Invalid query");
// the generation at query time, so NMT will spin till this generation is processed
unsigned long generation_at_query_time = SequenceGenerator::current_generation();
@@ -641,7 +641,7 @@
// compare memory usage between current snapshot and baseline
bool MemTracker::compare_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only) {
- MutexLockerEx lock(_query_lock, true);
+ MutexLocker lock(_query_lock);
if (_baseline.baselined()) {
MemBaseline baseline;
MemSnapshot* snapshot = get_snapshot();
--- a/hotspot/src/share/vm/utilities/debug.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/utilities/debug.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -229,11 +229,11 @@
}
void report_vm_out_of_memory(const char* file, int line, size_t size,
- const char* message) {
+ VMErrorType vm_err_type, const char* message) {
if (Debugging) return;
Thread* thread = ThreadLocalStorage::get_thread_slow();
- VMError(thread, file, line, size, message).report_and_die();
+ VMError(thread, file, line, size, vm_err_type, message).report_and_die();
// The UseOSErrorReporting option in report_and_die() may allow a return
// to here. If so then we'll have to figure out how to handle it.
@@ -344,7 +344,7 @@
msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
msg, eol, msg, eol, msg, eol, msg, eol, msg));
- case 8: vm_exit_out_of_memory(num, "ChunkPool::allocate");
+ case 8: vm_exit_out_of_memory(num, OOM_MALLOC_ERROR, "ChunkPool::allocate");
case 9: ShouldNotCallThis();
case 10: ShouldNotReachHere();
case 11: Unimplemented();
--- a/hotspot/src/share/vm/utilities/debug.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/utilities/debug.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -174,9 +174,9 @@
} while (0)
// out of memory
-#define vm_exit_out_of_memory(size, msg) \
+#define vm_exit_out_of_memory(size, vm_err_type, msg) \
do { \
- report_vm_out_of_memory(__FILE__, __LINE__, size, msg); \
+ report_vm_out_of_memory(__FILE__, __LINE__, size, vm_err_type, msg); \
BREAKPOINT; \
} while (0)
@@ -204,12 +204,20 @@
BREAKPOINT; \
} while (0);
+
+// types of VM error - originally in vmError.hpp
+enum VMErrorType {
+ INTERNAL_ERROR = 0xe0000000,
+ OOM_MALLOC_ERROR = 0xe0000001,
+ OOM_MMAP_ERROR = 0xe0000002
+};
+
// error reporting helper functions
void report_vm_error(const char* file, int line, const char* error_msg,
const char* detail_msg = NULL);
void report_fatal(const char* file, int line, const char* message);
void report_vm_out_of_memory(const char* file, int line, size_t size,
- const char* message);
+ VMErrorType vm_err_type, const char* message);
void report_should_not_call(const char* file, int line);
void report_should_not_reach_here(const char* file, int line);
void report_unimplemented(const char* file, int line);
--- a/hotspot/src/share/vm/utilities/ostream.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/utilities/ostream.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -196,7 +196,7 @@
fileStream() { _file = NULL; _need_close = false; }
fileStream(const char* file_name);
fileStream(const char* file_name, const char* opentype);
- fileStream(FILE* file) { _file = file; _need_close = false; }
+ fileStream(FILE* file, bool need_close = false) { _file = file; _need_close = need_close; }
~fileStream();
bool is_open() const { return _file != NULL; }
void set_need_close(bool b) { _need_close = b;}
--- a/hotspot/src/share/vm/utilities/vmError.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/utilities/vmError.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -100,7 +100,7 @@
const char* message, const char * detail_msg)
{
_thread = thread;
- _id = internal_error; // Value that's not an OS exception/signal
+ _id = INTERNAL_ERROR; // Value that's not an OS exception/signal
_filename = filename;
_lineno = lineno;
_message = message;
@@ -119,9 +119,9 @@
// Constructor for OOM errors
VMError::VMError(Thread* thread, const char* filename, int lineno, size_t size,
- const char* message) {
+ VMErrorType vm_err_type, const char* message) {
_thread = thread;
- _id = oom_error; // Value that's not an OS exception/signal
+ _id = vm_err_type; // Value that's not an OS exception/signal
_filename = filename;
_lineno = lineno;
_message = message;
@@ -142,7 +142,7 @@
// Constructor for non-fatal errors
VMError::VMError(const char* message) {
_thread = NULL;
- _id = internal_error; // Value that's not an OS exception/signal
+ _id = INTERNAL_ERROR; // Value that's not an OS exception/signal
_filename = NULL;
_lineno = 0;
_message = message;
@@ -351,9 +351,12 @@
STEP(15, "(printing type of error)")
switch(_id) {
- case oom_error:
+ case OOM_MALLOC_ERROR:
+ case OOM_MMAP_ERROR:
if (_size) {
- st->print("# Native memory allocation (malloc) failed to allocate ");
+ st->print("# Native memory allocation ");
+ st->print((_id == (int)OOM_MALLOC_ERROR) ? "(malloc) failed to allocate " :
+ "(mmap) failed to map ");
jio_snprintf(buf, sizeof(buf), SIZE_FORMAT, _size);
st->print(buf);
st->print(" bytes");
@@ -386,7 +389,7 @@
return; // that's enough for the screen
}
break;
- case internal_error:
+ case INTERNAL_ERROR:
default:
break;
}
@@ -796,6 +799,56 @@
VMError* volatile VMError::first_error = NULL;
volatile jlong VMError::first_error_tid = -1;
+/** Expand a pattern into a buffer starting at pos and open a file using constructed path */
+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)) {
+ fd = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0666);
+ }
+ return fd;
+}
+
+/**
+ * Construct file name for a log file and return it's file descriptor.
+ * Name and location depends on pattern, default_pattern params and access
+ * permissions.
+ */
+static int prepare_log_file(const char* pattern, const char* default_pattern, char* buf, size_t buflen) {
+ int fd = -1;
+
+ // If possible, use specified pattern to construct log file name
+ if (pattern != NULL) {
+ fd = expand_and_open(pattern, buf, buflen, 0);
+ }
+
+ // Either user didn't specify, or the user's location failed,
+ // so use the default name in the current directory
+ if (fd == -1) {
+ const char* cwd = os::get_current_directory(buf, buflen);
+ if (cwd != NULL) {
+ size_t pos = strlen(cwd);
+ int fsep_len = jio_snprintf(&buf[pos], buflen-pos, "%s", os::file_separator());
+ pos += fsep_len;
+ if (fsep_len > 0) {
+ fd = expand_and_open(default_pattern, buf, buflen, pos);
+ }
+ }
+ }
+
+ // try temp directory if it exists.
+ if (fd == -1) {
+ const char* tmpdir = os::get_temp_directory();
+ if (tmpdir != NULL && strlen(tmpdir) > 0) {
+ int pos = jio_snprintf(buf, buflen, "%s%s", tmpdir, os::file_separator());
+ if (pos > 0) {
+ fd = expand_and_open(default_pattern, buf, buflen, pos);
+ }
+ }
+ }
+
+ return fd;
+}
+
void VMError::report_and_die() {
// Don't allocate large buffer on stack
static char buffer[O_BUFLEN];
@@ -905,36 +958,7 @@
// see if log file is already open
if (!log.is_open()) {
// open log file
- int fd = -1;
-
- if (ErrorFile != NULL) {
- bool copy_ok =
- Arguments::copy_expand_pid(ErrorFile, strlen(ErrorFile), buffer, sizeof(buffer));
- if (copy_ok) {
- fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666);
- }
- }
-
- if (fd == -1) {
- const char *cwd = os::get_current_directory(buffer, sizeof(buffer));
- size_t len = strlen(cwd);
- // either user didn't specify, or the user's location failed,
- // so use the default name in the current directory
- jio_snprintf(&buffer[len], sizeof(buffer)-len, "%shs_err_pid%u.log",
- os::file_separator(), os::current_process_id());
- fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666);
- }
-
- if (fd == -1) {
- const char * tmpdir = os::get_temp_directory();
- // try temp directory if it exists.
- if (tmpdir != NULL && tmpdir[0] != '\0') {
- jio_snprintf(buffer, sizeof(buffer), "%s%shs_err_pid%u.log",
- tmpdir, os::file_separator(), os::current_process_id());
- fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666);
- }
- }
-
+ int fd = prepare_log_file(ErrorFile, "hs_err_pid%p.log", buffer, sizeof(buffer));
if (fd != -1) {
out.print_raw("# An error report file with more information is saved as:\n# ");
out.print_raw_cr(buffer);
@@ -958,7 +982,7 @@
// Run error reporting to determine whether or not to report the crash.
if (!transmit_report_done && should_report_bug(first_error->_id)) {
transmit_report_done = true;
- FILE* hs_err = ::fdopen(log.fd(), "r");
+ FILE* hs_err = os::open(log.fd(), "r");
if (NULL != hs_err) {
ErrorReporter er;
er.call(hs_err, buffer, O_BUFLEN);
@@ -1008,7 +1032,19 @@
skip_replay = true;
ciEnv* env = ciEnv::current();
if (env != NULL) {
- env->dump_replay_data();
+ int fd = prepare_log_file(ReplayDataFile, "replay_pid%p.log", buffer, sizeof(buffer));
+ if (fd != -1) {
+ FILE* replay_data_file = os::open(fd, "w");
+ if (replay_data_file != NULL) {
+ fileStream replay_data_stream(replay_data_file, /*need_close=*/true);
+ env->dump_replay_data(&replay_data_stream);
+ out.print_raw("#\n# Compiler replay data is saved as:\n# ");
+ out.print_raw_cr(buffer);
+ } else {
+ out.print_raw("#\n# Can't open file to dump replay data. Error: ");
+ out.print_raw_cr(strerror(os::get_last_error()));
+ }
+ }
}
}
--- a/hotspot/src/share/vm/utilities/vmError.hpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/utilities/vmError.hpp Wed Jul 05 18:53:57 2017 +0200
@@ -34,10 +34,6 @@
friend class VM_ReportJavaOutOfMemory;
friend class Decoder;
- enum ErrorType {
- internal_error = 0xe0000000,
- oom_error = 0xe0000001
- };
int _id; // Solaris/Linux signals: 0 - SIGRTMAX
// Windows exceptions: 0xCxxxxxxx system errors
// 0x8xxxxxxx system warnings
@@ -96,9 +92,12 @@
// accessor
const char* message() const { return _message; }
const char* detail_msg() const { return _detail_msg; }
- bool should_report_bug(unsigned int id) { return id != oom_error; }
+ bool should_report_bug(unsigned int id) {
+ return (id != OOM_MALLOC_ERROR) && (id != OOM_MMAP_ERROR);
+ }
public:
+
// Constructor for crashes
VMError(Thread* thread, unsigned int sig, address pc, void* siginfo,
void* context);
@@ -108,7 +107,7 @@
// Constructor for VM OOM errors
VMError(Thread* thread, const char* filename, int lineno, size_t size,
- const char* message);
+ VMErrorType vm_err_type, const char* message);
// Constructor for non-fatal errors
VMError(const char* message);
--- a/hotspot/src/share/vm/utilities/workgroup.cpp Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/src/share/vm/utilities/workgroup.cpp Wed Jul 05 18:53:57 2017 +0200
@@ -79,7 +79,7 @@
}
_gang_workers = NEW_C_HEAP_ARRAY(GangWorker*, total_workers(), mtInternal);
if (gang_workers() == NULL) {
- vm_exit_out_of_memory(0, "Cannot create GangWorker array.");
+ vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GangWorker array.");
return false;
}
os::ThreadType worker_type;
@@ -93,7 +93,8 @@
assert(new_worker != NULL, "Failed to allocate GangWorker");
_gang_workers[worker] = new_worker;
if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) {
- vm_exit_out_of_memory(0, "Cannot create worker GC thread. Out of system resources.");
+ vm_exit_out_of_memory(0, OOM_MALLOC_ERROR,
+ "Cannot create worker GC thread. Out of system resources.");
return false;
}
if (!DisableStartThread) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/ciReplay/TestSA.sh Wed Jul 05 18:53:57 2017 +0200
@@ -0,0 +1,92 @@
+#!/bin/sh
+#
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# 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 8011675
+## @summary testing of ciReplay with using generated by SA replay.txt
+## @author igor.ignatyev@oracle.com
+## @run shell TestSA.sh
+##
+
+if [ "${TESTSRC}" = "" ]
+then
+ TESTSRC=${PWD}
+ echo "TESTSRC not set. Using "${TESTSRC}" as default"
+fi
+echo "TESTSRC=${TESTSRC}"
+
+## Adding common setup Variables for running shell tests.
+. ${TESTSRC}/../../test_env.sh
+
+. ${TESTSRC}/common.sh
+
+generate_replay
+
+${MV} ${replay_data} replay_vm.txt
+
+if [ -z "${core_file}" -o ! -r "${core_file}" ]
+then
+ # skip test if MacOS host isn't configured for core dumping
+ if [ "$OS" = "Darwin" ]
+ then
+ if [ ! -d "/cores" ]
+ then
+ echo TEST SKIPPED: \'/cores\' dir doens\'t exist
+ exit 0
+ fi
+ if [ ! -w "/cores" ]
+ then
+ echo TEST SKIPPED: \'/cores\' dir exists but is not writable
+ exit 0
+ fi
+ fi
+ test_fail 2 "CHECK :: CORE GENERATION" "core wasn't generated on $OS"
+fi
+
+echo "dumpreplaydata -a > ${replay_data}" | \
+ ${JAVA} ${TESTVMOPTS} \
+ -cp ${TESTJAVA}${FS}lib${FS}sa-jdi.jar \
+ sun.jvm.hotspot.CLHSDB ${JAVA} ${core_file}
+
+if [ ! -s ${replay_data} ]
+then
+ test_fail 1 "CHECK :: REPLAY DATA GENERATION" \
+ "replay data wasn't generated by SA"
+fi
+
+diff --brief ${replay_data} replay_vm.txt
+if [ $? -ne 0 ]
+then
+ echo WARNING: replay.txt from SA != replay.txt from VM
+fi
+
+common_tests 10
+${VM_TYPE}_tests 20
+
+cleanup
+
+echo TEST PASSED
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/ciReplay/TestVM.sh Wed Jul 05 18:53:57 2017 +0200
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# 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 8011675
+## @summary testing of ciReplay with using generated by VM replay.txt
+## @author igor.ignatyev@oracle.com
+## @run shell TestVM.sh
+##
+
+if [ "${TESTSRC}" = "" ]
+then
+ TESTSRC=${PWD}
+ echo "TESTSRC not set. Using "${TESTSRC}" as default"
+fi
+echo "TESTSRC=${TESTSRC}"
+
+## Adding common setup Variables for running shell tests.
+. ${TESTSRC}/../../test_env.sh
+
+. ${TESTSRC}/common.sh
+
+generate_replay
+
+if [ ! -s ${replay_data} ]
+then
+ test_fail 1 "CHECK :: REPLAY DATA GENERATION" \
+ "replay data wasn't generated by VM"
+fi
+
+common_tests 10
+${VM_TYPE}_tests 20
+
+cleanup
+
+if [ $is_tiered -eq 1 ]
+then
+ stop_level=1
+ while [ $stop_level -le $server_level ]
+ do
+ generate_replay "-XX:TieredStopAtLevel=$stop_level"
+ if [ ! -s ${replay_data} ]
+ then
+ test_fail `expr $stop_level + 30` \
+ "TIERED LEVEL $stop_level :: REPLAY DATA GENERATION" \
+ "replay data wasn't generated by VM with stop_level=$stop_level"
+ fi
+ level=`grep "^compile " $replay_data | awk '{print $6}'`
+ if [ $level -gt $stop_level ]
+ then
+ test_fail `expr $stop_level + 40` \
+ "TIERED LEVEL $stop_level :: COMP_LEVEL VERIFICATION" \
+ "comp_level in replay[$level] is greater than stop_level[$stop_level]"
+ fi
+ positive_test `expr $stop_level + 50` "TIERED LEVEL $stop_level :: REPLAY" \
+ "-XX:TieredStopAtLevel=$stop_level"
+ stop_level=`expr $stop_level + 1`
+ done
+ cleanup
+fi
+
+echo TEST PASSED
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/ciReplay/TestVM_no_comp_level.sh Wed Jul 05 18:53:57 2017 +0200
@@ -0,0 +1,74 @@
+#!/bin/sh
+#
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# 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 8011675
+## @summary testing of ciReplay with using generated by VM replay.txt w/o comp_level
+## @author igor.ignatyev@oracle.com
+## @run shell TestVM_no_comp_level.sh
+##
+
+if [ "${TESTSRC}" = "" ]
+then
+ TESTSRC=${PWD}
+ echo "TESTSRC not set. Using "${TESTSRC}" as default"
+fi
+echo "TESTSRC=${TESTSRC}"
+
+## Adding common setup Variables for running shell tests.
+. ${TESTSRC}/../../test_env.sh
+
+. ${TESTSRC}/common.sh
+
+generate_replay
+
+if [ ! -s ${replay_data} ]
+then
+ test_fail 1 "CHECK :: REPLAY DATA GENERATION" \
+ "replay data wasn't generated by VM"
+fi
+
+${CP} ${replay_data} replay_vm.txt
+
+sed 's/^\(compile *[^ ][^ ]* *[^ ][^ ]* [^ ][^ ]* [^ ][^ ]*\).*$/\1/' \
+ replay_vm.txt > ${replay_data}
+
+if [ $client_available -eq 1 ]
+then
+ # tiered is unavailable in client vm, so results w/ flags will be the same as w/o flags
+ negative_test 10 "CLIENT" -client
+fi
+
+if [ $server_available -eq 1 ]
+then
+ positive_test 21 "SERVER :: NON-TIERED" -XX:-TieredCompilation -server
+ positive_test 22 "SERVER :: TIERED" -XX:+TieredCompilation -server
+fi
+
+cleanup
+
+echo TEST PASSED
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/ciReplay/common.sh Wed Jul 05 18:53:57 2017 +0200
@@ -0,0 +1,253 @@
+#!/bin/sh
+#
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# 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.
+#
+#
+
+# $1 - error code
+# $2 - test name
+# $3,.. - decription
+test_fail() {
+ error=$1
+ shift
+ name=$1
+ shift
+ echo "TEST [$name] FAILED:"
+ echo "$@"
+ exit $error
+}
+
+# $@ - additional vm opts
+start_test() {
+ # disable core dump on *nix
+ ulimit -S -c 0
+ # disable core dump on windows
+ VMOPTS="$@ -XX:-CreateMinidumpOnCrash"
+ cmd="${JAVA} ${VMOPTS} -XX:+ReplayCompiles -XX:ReplayDataFile=${replay_data}"
+ echo $cmd
+ $cmd
+ return $?
+}
+
+# $1 - error_code
+# $2 - test name
+# $3,.. - additional vm opts
+positive_test() {
+ error=$1
+ shift
+ name=$1
+ shift
+ VMOPTS="${TESTVMOPTS} $@"
+ echo "POSITIVE TEST [$name]"
+ start_test ${VMOPTS}
+ exit_code=$?
+ if [ ${exit_code} -ne 0 ]
+ then
+ test_fail $error "$name" "exit_code[${exit_code}] != 0 during replay "\
+ "w/ vmopts: ${VMOPTS}"
+ fi
+}
+
+# $1 - error_code
+# $2 - test name
+# $2,.. - additional vm opts
+negative_test() {
+ error=$1
+ shift
+ name=$1
+ shift
+ VMOPTS="${TESTVMOPTS} $@"
+ echo "NEGATIVE TEST [$name]"
+ start_test ${VMOPTS}
+ exit_code=$?
+ if [ ${exit_code} -eq 0 ]
+ then
+ test_fail $error "$name" "exit_code[${exit_code}] == 0 during replay "\
+ "w/ vmopts: ${VMOPTS}"
+ fi
+}
+
+# $1 - initial error_code
+common_tests() {
+ positive_test $1 "COMMON :: THE SAME FLAGS"
+ positive_test `expr $1 + 1` "COMMON :: TIERED" -XX:+TieredCompilation
+}
+
+# $1 - initial error_code
+# $2 - non-tiered comp_level
+nontiered_tests() {
+ level=`grep "^compile " $replay_data | awk '{print $6}'`
+ # is level available in non-tiere
+ if [ "$level" -eq $2 ]
+ then
+ positive_test $1 "NON-TIERED :: AVAILABLE COMP_LEVEL" \
+ -XX:-TieredCompilation
+ else
+ negative_test `expr $1 + 1` "NON-TIERED :: UNAVAILABLE COMP_LEVEL" \
+ negative_test `expr $1 + 1` "NON-TIERED :: UNAVAILABLE COMP_LEVEL" \
+ -XX:-TieredCompilation
+ fi
+}
+
+# $1 - initial error_code
+client_tests() {
+ # testing in opposite VM
+ if [ $server_available -eq 1 ]
+ then
+ negative_test $1 "SERVER :: NON-TIERED" -XX:-TieredCompilation \
+ -server
+ positive_test `expr $1 + 1` "SERVER :: TIERED" -XX:+TieredCompilation \
+ -server
+ fi
+ nontiered_tests `expr $1 + 2` $client_level
+}
+
+# $1 - initial error_code
+server_tests() {
+ # testing in opposite VM
+ if [ $client_available -eq 1 ]
+ then
+ # tiered is unavailable in client vm, so results w/ flags will be the same as w/o flags
+ negative_test $1 "CLIENT" -client
+ fi
+ nontiered_tests `expr $1 + 2` $server_level
+}
+
+cleanup() {
+ ${RM} -f core*
+ ${RM} -f replay*.txt
+ ${RM} -f hs_err_pid*.log
+ ${RM} -f test_core
+ ${RM} -f test_replay.txt
+}
+
+JAVA=${TESTJAVA}${FS}bin${FS}java
+
+replay_data=test_replay.txt
+
+${JAVA} ${TESTVMOPTS} -Xinternalversion 2>&1 | grep debug
+
+# Only test fastdebug
+if [ $? -ne 0 ]
+then
+ echo TEST SKIPPED: product build
+ exit 0
+fi
+
+is_int=`${JAVA} ${TESTVMOPTS} -version 2>&1 | grep -c "interpreted mode"`
+# Not applicable for Xint
+if [ $is_int -ne 0 ]
+then
+ echo TEST SKIPPED: interpreted mode
+ exit 0
+fi
+
+cleanup
+
+client_available=`${JAVA} ${TESTVMOPTS} -client -Xinternalversion 2>&1 | \
+ grep -c Client`
+server_available=`${JAVA} ${TESTVMOPTS} -server -Xinternalversion 2>&1 | \
+ grep -c Server`
+is_tiered=`${JAVA} ${TESTVMOPTS} -XX:+PrintFlagsFinal -version | \
+ grep TieredCompilation | \
+ grep -c true`
+# CompLevel_simple -- C1
+client_level=1
+# CompLevel_full_optimization -- C2 or Shark
+server_level=4
+
+echo "client_available=$client_available"
+echo "server_available=$server_available"
+echo "is_tiered=$is_tiered"
+
+# crash vm in compiler thread with generation replay data and 'small' dump-file
+# $@ - additional vm opts
+generate_replay() {
+ # enable core dump
+ ulimit -c unlimited
+
+ cmd="${JAVA} ${TESTVMOPTS} $@ \
+ -Xms8m \
+ -Xmx32m \
+ -XX:MetaspaceSize=4m \
+ -XX:MaxMetaspaceSize=16m \
+ -XX:InitialCodeCacheSize=512k \
+ -XX:ReservedCodeCacheSize=4m \
+ -XX:ThreadStackSize=512 \
+ -XX:VMThreadStackSize=512 \
+ -XX:CompilerThreadStackSize=512 \
+ -XX:ParallelGCThreads=1 \
+ -XX:CICompilerCount=1 \
+ -Xcomp \
+ -XX:CICrashAt=1 \
+ -XX:+CreateMinidumpOnCrash \
+ -XX:+DumpReplayDataOnError \
+ -XX:ReplayDataFile=${replay_data} \
+ -version"
+ echo GENERATION OF REPLAY.TXT:
+ echo $cmd
+
+ ${cmd} 2>&1 > crash.out
+
+ core_locations=`grep -i core crash.out | grep "location:" | \
+ sed -e 's/.*location: //'`
+ rm crash.out
+ # processing core locations for *nix
+ if [ $OS != "windows" ]
+ then
+ # remove 'or' between '/core.<pid>' and 'core'
+ core_locations=`echo $core_locations | \
+ sed -e 's/\([^ ]*\) or \([^ ]*\)/\1 \2/'`
+ # add <core_path>/core.<pid> core.<pid>
+ core=`echo $core_locations | awk '{print $1}'`
+ dir=`dirname $core`
+ core=`basename $core`
+ if [ -n ${core} ]
+ then
+ core_locations="$core_locations $dir${FS}$core"
+ fi
+ core=`echo $core_locations | awk '{print $2}'`
+ if [ -n ${core} ]
+ then
+ core_locations="$core_locations $dir${FS}$core"
+ fi
+ fi
+
+ echo "LOOKING FOR CORE IN ${core_locations}"
+ for core in $core_locations
+ do
+ if [ -r "$core" ]
+ then
+ core_file=$core
+ fi
+ done
+
+ # core-file was found
+ if [ -n "$core_file" ]
+ then
+ ${MV} "${core_file}" test_core
+ core_file=test_core
+ fi
+
+ ${RM} -f hs_err_pid*.log
+}
+
--- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java Wed Jul 05 18:53:57 2017 +0200
@@ -42,6 +42,11 @@
protected static int COMP_LEVEL_NONE = 0;
/** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */
protected static int COMP_LEVEL_ANY = -1;
+ /** {@code CompLevel::CompLevel_simple} -- C1 */
+ protected static int COMP_LEVEL_SIMPLE = 1;
+ /** {@code CompLevel::CompLevel_full_optimization} -- C2 or Shark */
+ protected static int COMP_LEVEL_FULL_OPTIMIZATION = 4;
+
/** Instance of WhiteBox */
protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
/** Value of {@code -XX:CompileThreshold} */
@@ -91,6 +96,17 @@
return result == null ? defaultValue : result;
}
+ /** copy of is_c1_compile(int) from utilities/globalDefinitions.hpp */
+ protected static boolean isC1Compile(int compLevel) {
+ return (compLevel > COMP_LEVEL_NONE)
+ && (compLevel < COMP_LEVEL_FULL_OPTIMIZATION);
+ }
+
+ /** copy of is_c2_compile(int) from utilities/globalDefinitions.hpp */
+ protected static boolean isC2Compile(int compLevel) {
+ return compLevel == COMP_LEVEL_FULL_OPTIMIZATION;
+ }
+
/** tested method */
protected final Executable method;
private final Callable<Integer> callable;
--- a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java Wed Jul 05 18:53:57 2017 +0200
@@ -23,6 +23,7 @@
/*
* @test MakeMethodNotCompilableTest
+ * @bug 8012322
* @library /testlibrary /testlibrary/whitebox
* @build MakeMethodNotCompilableTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
@@ -67,28 +68,69 @@
}
if (TIERED_COMPILATION) {
- for (int i = 1, n = TIERED_STOP_AT_LEVEL + 1; i < n; ++i) {
- WHITE_BOX.makeMethodNotCompilable(method, i);
- if (WHITE_BOX.isMethodCompilable(method, i)) {
+ final int tierLimit = TIERED_STOP_AT_LEVEL + 1;
+ for (int testedTier = 1; testedTier < tierLimit; ++testedTier) {
+ testTier(testedTier);
+ }
+ for (int testedTier = 1; testedTier < tierLimit; ++testedTier) {
+ WHITE_BOX.makeMethodNotCompilable(method, testedTier);
+ if (WHITE_BOX.isMethodCompilable(method, testedTier)) {
throw new RuntimeException(method
- + " must be not compilable at level" + i);
+ + " must be not compilable at level" + testedTier);
}
- WHITE_BOX.enqueueMethodForCompilation(method, i);
+ WHITE_BOX.enqueueMethodForCompilation(method, testedTier);
checkNotCompiled();
if (!WHITE_BOX.isMethodCompilable(method)) {
System.out.println(method
- + " is not compilable after level " + i);
+ + " is not compilable after level " + testedTier);
}
}
+ } else {
+ compile();
+ checkCompiled();
+ int compLevel = WHITE_BOX.getMethodCompilationLevel(method);
+ WHITE_BOX.deoptimizeMethod(method);
+ WHITE_BOX.makeMethodNotCompilable(method, compLevel);
+ if (WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY)) {
+ throw new RuntimeException(method
+ + " must be not compilable at CompLevel::CompLevel_any,"
+ + " after it is not compilable at " + compLevel);
+ }
+ WHITE_BOX.clearMethodState(method);
+
+ // nocompilable at opposite level must make no sense
+ int oppositeLevel;
+ if (isC1Compile(compLevel)) {
+ oppositeLevel = COMP_LEVEL_FULL_OPTIMIZATION;
+ } else {
+ oppositeLevel = COMP_LEVEL_SIMPLE;
+ }
+ WHITE_BOX.makeMethodNotCompilable(method, oppositeLevel);
+
+ if (!WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY)) {
+ throw new RuntimeException(method
+ + " must be compilable at CompLevel::CompLevel_any,"
+ + " even it is not compilable at opposite level ["
+ + compLevel + "]");
+ }
- // WB.clearMethodState() must reset no-compilable flags
- WHITE_BOX.clearMethodState(method);
- if (!WHITE_BOX.isMethodCompilable(method)) {
- throw new RuntimeException(method
- + " is not compilable after clearMethodState()");
+ if (!WHITE_BOX.isMethodCompilable(method, compLevel)) {
+ throw new RuntimeException(method
+ + " must be compilable at level " + compLevel
+ + ", even it is not compilable at opposite level ["
+ + compLevel + "]");
}
}
+
+ // clearing after tiered/non-tiered tests
+ // WB.clearMethodState() must reset no-compilable flags
+ WHITE_BOX.clearMethodState(method);
+ if (!WHITE_BOX.isMethodCompilable(method)) {
+ throw new RuntimeException(method
+ + " is not compilable after clearMethodState()");
+ }
+
WHITE_BOX.makeMethodNotCompilable(method);
if (WHITE_BOX.isMethodCompilable(method)) {
throw new RuntimeException(method + " must be not compilable");
@@ -108,4 +150,65 @@
compile();
checkCompiled();
}
+
+ // separately tests each tier
+ private void testTier(int testedTier) {
+ if (!WHITE_BOX.isMethodCompilable(method, testedTier)) {
+ throw new RuntimeException(method
+ + " is not compilable on start");
+ }
+ WHITE_BOX.makeMethodNotCompilable(method, testedTier);
+
+ // tests for all other tiers
+ for (int anotherTier = 1, tierLimit = TIERED_STOP_AT_LEVEL + 1;
+ anotherTier < tierLimit; ++anotherTier) {
+ boolean isCompilable = WHITE_BOX.isMethodCompilable(method,
+ anotherTier);
+ if (sameCompile(testedTier, anotherTier)) {
+ if (isCompilable) {
+ throw new RuntimeException(method
+ + " must be not compilable at level " + anotherTier
+ + ", if it is not compilable at " + testedTier);
+ }
+ WHITE_BOX.enqueueMethodForCompilation(method, anotherTier);
+ checkNotCompiled();
+ } else {
+ if (!isCompilable) {
+ throw new RuntimeException(method
+ + " must be compilable at level " + anotherTier
+ + ", even if it is not compilable at "
+ + testedTier);
+ }
+ WHITE_BOX.enqueueMethodForCompilation(method, anotherTier);
+ checkCompiled();
+ WHITE_BOX.deoptimizeMethod(method);
+ }
+
+ if (!WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY)) {
+ throw new RuntimeException(method
+ + " must be compilable at 'CompLevel::CompLevel_any'"
+ + ", if it is not compilable only at " + testedTier);
+ }
+ }
+
+ // clear state after test
+ WHITE_BOX.clearMethodState(method);
+ if (!WHITE_BOX.isMethodCompilable(method, testedTier)) {
+ throw new RuntimeException(method
+ + " is not compilable after clearMethodState()");
+ }
+ }
+
+ private boolean sameCompile(int level1, int level2) {
+ if (level1 == level2) {
+ return true;
+ }
+ if (isC1Compile(level1) && isC1Compile(level2)) {
+ return true;
+ }
+ if (isC2Compile(level1) && isC2Compile(level2)) {
+ return true;
+ }
+ return false;
+ }
}
--- a/hotspot/test/gc/7072527/TestFullGCCount.java Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/test/gc/7072527/TestFullGCCount.java Wed Jul 05 18:53:57 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* 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,71 +25,67 @@
* @test TestFullGCount.java
* @bug 7072527
* @summary CMS: JMM GC counters overcount in some cases
- * @run main/othervm -XX:+UseConcMarkSweepGC TestFullGCCount
- *
+ * @run main/othervm -XX:+PrintGC TestFullGCCount
*/
import java.util.*;
import java.lang.management.*;
+/*
+ * Originally for a specific failure in CMS, this test now monitors all
+ * collectors for double-counting of collections.
+ */
public class TestFullGCCount {
- public String collectorName = "ConcurrentMarkSweep";
-
- public static void main(String [] args) {
+ static List<GarbageCollectorMXBean> collectors = ManagementFactory.getGarbageCollectorMXBeans();
- TestFullGCCount t = null;
- if (args.length==2) {
- t = new TestFullGCCount(args[0], args[1]);
- } else {
- t = new TestFullGCCount();
+ public static void main(String[] args) {
+ int iterations = 20;
+ boolean failed = false;
+ String errorMessage = "";
+ HashMap<String, List> counts = new HashMap<String, List>();
+
+ // Prime the collection of count lists for all collectors.
+ for (int i = 0; i < collectors.size(); i++) {
+ GarbageCollectorMXBean collector = collectors.get(i);
+ counts.put(collector.getName(), new ArrayList<Long>(iterations));
}
- System.out.println("Monitoring collector: " + t.collectorName);
- t.run();
- }
- public TestFullGCCount(String pool, String collector) {
- collectorName = collector;
- }
-
- public TestFullGCCount() {
- }
+ // Perform some gc, record collector counts.
+ for (int i = 0; i < iterations; i++) {
+ System.gc();
+ addCollectionCount(counts, i);
+ }
- public void run() {
- int count = 0;
- int iterations = 20;
- long counts[] = new long[iterations];
- boolean diffAlways2 = true; // assume we will fail
+ // Check the increments:
+ // Old gen collectors should increase by one,
+ // New collectors may or may not increase.
+ // Any increase >=2 is unexpected.
+ for (String collector : counts.keySet()) {
+ System.out.println("Checking: " + collector);
- for (int i=0; i<iterations; i++) {
- System.gc();
- counts[i] = getCollectionCount();
- if (i>0) {
- if (counts[i] - counts[i-1] != 2) {
- diffAlways2 = false;
+ for (int i = 0; i < iterations - 1; i++) {
+ List<Long> theseCounts = counts.get(collector);
+ long a = theseCounts.get(i);
+ long b = theseCounts.get(i + 1);
+ if (b - a >= 2) {
+ failed = true;
+ errorMessage += "Collector '" + collector + "' has increment " + (b - a) +
+ " at iteration " + i + "\n";
}
}
}
- if (diffAlways2) {
- throw new RuntimeException("FAILED: System.gc must be incrementing count twice.");
+ if (failed) {
+ System.err.println(errorMessage);
+ throw new RuntimeException("FAILED: System.gc collections miscounted.");
}
System.out.println("Passed.");
}
- private long getCollectionCount() {
- long count = 0;
- List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
- List<GarbageCollectorMXBean> collectors = ManagementFactory.getGarbageCollectorMXBeans();
- for (int i=0; i<collectors.size(); i++) {
+ private static void addCollectionCount(HashMap<String, List> counts, int iteration) {
+ for (int i = 0; i < collectors.size(); i++) {
GarbageCollectorMXBean collector = collectors.get(i);
- String name = collector.getName();
- if (name.contains(collectorName)) {
- System.out.println(name + ": collection count = "
- + collector.getCollectionCount());
- count = collector.getCollectionCount();
- }
+ List thisList = counts.get(collector.getName());
+ thisList.add(collector.getCollectionCount());
}
- return count;
}
-
}
-
--- a/hotspot/test/gc/TestVerifyDuringStartup.java Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/test/gc/TestVerifyDuringStartup.java Wed Jul 05 18:53:57 2017 +0200
@@ -23,22 +23,43 @@
/* @test TestVerifyDuringStartup.java
* @key gc
- * @bug 8010463
+ * @bug 8010463 8011343 8011898
* @summary Simple test run with -XX:+VerifyDuringStartup -XX:-UseTLAB to verify 8010463
* @library /testlibrary
*/
+import com.oracle.java.testlibrary.JDKToolFinder;
import com.oracle.java.testlibrary.OutputAnalyzer;
import com.oracle.java.testlibrary.ProcessTools;
+import java.util.ArrayList;
+import java.util.Collections;
public class TestVerifyDuringStartup {
public static void main(String args[]) throws Exception {
+ ArrayList<String> vmOpts = new ArrayList();
+
+ String testVmOptsStr = System.getProperty("test.java.opts");
+ if (!testVmOptsStr.isEmpty()) {
+ String[] testVmOpts = testVmOptsStr.split(" ");
+ Collections.addAll(vmOpts, testVmOpts);
+ }
+ Collections.addAll(vmOpts, new String[] {"-XX:-UseTLAB",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+VerifyDuringStartup",
+ "-version"});
+
+ System.out.print("Testing:\n" + JDKToolFinder.getJDKTool("java"));
+ for (int i = 0; i < vmOpts.size(); i += 1) {
+ System.out.print(" " + vmOpts.get(i));
+ }
+ System.out.println();
+
ProcessBuilder pb =
- ProcessTools.createJavaProcessBuilder(System.getProperty("test.vm.opts"),
- "-XX:-UseTLAB",
- "-XX:+UnlockDiagnosticVMOptions",
- "-XX:+VerifyDuringStartup", "-version");
+ ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()]));
OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+ System.out.println("Output:\n" + output.getOutput());
+
output.shouldContain("[Verifying");
output.shouldHaveExitValue(0);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/concurrentMarkSweep/GuardShrinkWarning.java Wed Jul 05 18:53:57 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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 GuardShrinkWarning
+ * @summary Remove warning about CMS generation shrinking.
+ * @bug 8012111
+ * @key gc
+ * @key regression
+ * @library /testlibrary
+ * @run main/othervm GuardShrinkWarning
+ * @author jon.masamitsu@oracle.com
+ */
+
+import com.oracle.java.testlibrary.*;
+
+public class GuardShrinkWarning {
+ public static void main(String args[]) throws Exception {
+
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-showversion",
+ "-XX:+UseConcMarkSweepGC",
+ "-XX:+ExplicitGCInvokesConcurrent",
+ "GuardShrinkWarning$SystemGCCaller"
+ );
+
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+ output.shouldNotContain("Shrinking of CMS not yet implemented");
+
+ output.shouldNotContain("error");
+
+ output.shouldHaveExitValue(0);
+ }
+ static class SystemGCCaller {
+ public static void main(String [] args) {
+ System.gc();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/lambda-features/PublicStaticInterfaceMethodHandling.java Wed Jul 05 18:53:57 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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 8013418
+ * @summary [JDK 8] Test correct handling of static public interface methods
+ * @run main/othervm -Xverify:all PublicStaticInterfaceMethodHandling
+ */
+
+class TestClass implements InterfaceWithStaticAndDefaultMethods {
+}
+
+interface InterfaceWithStaticAndDefaultMethods {
+ public static String get() {
+ return "Hello from StaticMethodInInterface.get()";
+ }
+ default void default_method() {
+ System.out.println("Default method FunctionalInterface:default_method()");
+ }
+}
+
+public class PublicStaticInterfaceMethodHandling {
+ public static void main(String[] args) {
+ TestClass tc = new TestClass();
+ tc.default_method();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/memory/ReserveMemory.java Wed Jul 05 18:53:57 2017 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
+ * @key regression
+ * @bug 8012015
+ * @summary Make sure reserved (but uncommitted) memory is not accessible
+ * @library /testlibrary /testlibrary/whitebox
+ * @build ReserveMemory
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main ReserveMemory
+ */
+
+import com.oracle.java.testlibrary.*;
+
+import java.lang.reflect.Field;
+import sun.hotspot.WhiteBox;
+import sun.misc.Unsafe;
+
+public class ReserveMemory {
+ private static Unsafe getUnsafe() throws Exception {
+ Field f = Unsafe.class.getDeclaredField("theUnsafe");
+ f.setAccessible(true);
+ return (Unsafe)f.get(null);
+ }
+
+ private static boolean isWindows() {
+ return System.getProperty("os.name").toLowerCase().startsWith("win");
+ }
+
+ public static void main(String args[]) throws Exception {
+ if (args.length > 0) {
+ long address = WhiteBox.getWhiteBox().reserveMemory(4096);
+
+ System.out.println("Reserved memory at address: 0x" + Long.toHexString(address));
+ System.out.println("Will now read from the address, expecting a crash!");
+
+ int x = getUnsafe().getInt(address);
+
+ throw new Exception("Read of reserved/uncommitted memory unexpectedly succeeded, expected crash!");
+ }
+
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-Xbootclasspath/a:.",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ "ReserveMemory",
+ "test");
+
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ if (isWindows()) {
+ output.shouldContain("EXCEPTION_ACCESS_VIOLATION");
+ } else {
+ output.shouldContain("SIGSEGV");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/sanity/WhiteBox.java Wed Jul 05 18:53:57 2017 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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 WhiteBox
+ * @bug 8011675
+ * @summary verify that whitebox can be used even if not all functions are declared in java-part
+ * @author igor.ignatyev@oracle.com
+ * @library /testlibrary
+ * @compile WhiteBox.java
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI sun.hotspot.WhiteBox
+ * @clean sun.hotspot.WhiteBox
+ */
+
+package sun.hotspot;
+
+public class WhiteBox {
+ private static native void registerNatives();
+ static { registerNatives(); }
+ public native int notExistedMethod();
+ public native int getHeapOopSize();
+ public static void main(String[] args) {
+ WhiteBox wb = new WhiteBox();
+ if (wb.getHeapOopSize() < 0) {
+ throw new Error("wb.getHeapOopSize() < 0");
+ }
+ boolean catched = false;
+ try {
+ wb.notExistedMethod();
+ } catch (UnsatisfiedLinkError e) {
+ catched = true;
+ }
+ if (!catched) {
+ throw new Error("wb.notExistedMethod() was invoked");
+ }
+ }
+}
--- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Tue May 07 13:13:12 2013 -0700
+++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Wed Jul 05 18:53:57 2017 +0200
@@ -111,6 +111,9 @@
// Intered strings
public native boolean isInStringTable(String str);
+ // Memory
+ public native long reserveMemory(long size);
+
// force Full GC
public native void fullGC();
}