--- a/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m Thu May 02 19:28:59 2013 +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/src/os/bsd/vm/os_bsd.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Thu May 02 19:28:59 2013 +0200
@@ -2080,9 +2080,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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Thu May 02 19:28:59 2013 +0200
@@ -2906,9 +2906,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/solaris/vm/os_solaris.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Thu May 02 19:28:59 2013 +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)));
--- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Thu May 02 19:28:59 2013 +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/asm/assembler.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/asm/assembler.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/ci/ciEnv.cpp Thu May 02 19:28:59 2013 +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
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Thu May 02 19:28:59 2013 +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/classLoaderData.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Thu May 02 19:28:59 2013 +0200
@@ -280,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);
@@ -303,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;
--- a/hotspot/src/share/vm/classfile/dictionary.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/classfile/dictionary.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Thu May 02 19:28:59 2013 +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/stubs.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/code/stubs.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/code/vtableStubs.cpp Thu May 02 19:28:59 2013 +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/gc_implementation/g1/g1BlockOffsetTable.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu May 02 19:28:59 2013 +0200
@@ -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;
@@ -3607,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));
@@ -4390,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));
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Thu May 02 19:28:59 2013 +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.");
}
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/gcTaskThread.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/objectStartArray.cpp Thu May 02 19:28:59 2013 +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/interpreter/interpreterRuntime.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/memory/allocation.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/memory/allocation.hpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/memory/allocation.inline.hpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/memory/blockOffsetTable.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Thu May 02 19:28:59 2013 +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/oops/constantPool.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/oops/constantPool.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/oops/constantPool.hpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/oops/cpCache.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Thu May 02 19:28:59 2013 +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/oop.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/oops/oop.cpp Thu May 02 19:28:59 2013 +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/prims/jvmtiEnv.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/prims/whitebox.cpp Thu May 02 19:28:59 2013 +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
--- a/hotspot/src/share/vm/runtime/objectMonitor.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp Thu May 02 19:28:59 2013 +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/stubRoutines.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp Thu May 02 19:28:59 2013 +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/synchronizer.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/runtime/synchronizer.cpp Thu May 02 19:28:59 2013 +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/services/memBaseline.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/services/memBaseline.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/services/memBaseline.hpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/services/memTracker.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/utilities/debug.cpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/utilities/debug.hpp Thu May 02 19:28:59 2013 +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/vmError.cpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/utilities/vmError.cpp Thu May 02 19:28:59 2013 +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;
}
--- a/hotspot/src/share/vm/utilities/vmError.hpp Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/utilities/vmError.hpp Thu May 02 19:28:59 2013 +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 Apr 30 16:36:24 2013 +0200
+++ b/hotspot/src/share/vm/utilities/workgroup.cpp Thu May 02 19:28:59 2013 +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/runtime/memory/ReserveMemory.java Thu May 02 19:28:59 2013 +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");
+ }
+ }
+}
--- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Tue Apr 30 16:36:24 2013 +0200
+++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Thu May 02 19:28:59 2013 +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();
}