# HG changeset patch # User adlertz # Date 1380321783 25200 # Node ID 1c3486050433110c36e975755a5700c2ab7ee24c # Parent 510fbd28919ca9af9cbad14481c466c376239d5b# Parent a07c25e4f67e3d559ff165b5a848fd08a541e22e Merge diff -r 510fbd28919c -r 1c3486050433 agent/src/os/linux/ps_core.c --- a/agent/src/os/linux/ps_core.c Fri Sep 27 10:50:55 2013 +0200 +++ b/agent/src/os/linux/ps_core.c Fri Sep 27 15:43:03 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -698,29 +698,58 @@ // read segments of a shared object static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* lib_ehdr, uintptr_t lib_base) { - int i = 0; - ELF_PHDR* phbuf; - ELF_PHDR* lib_php = NULL; + int i = 0; + ELF_PHDR* phbuf; + ELF_PHDR* lib_php = NULL; + + int page_size=sysconf(_SC_PAGE_SIZE); - if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL) - return false; + if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL) { + return false; + } + + // we want to process only PT_LOAD segments that are not writable. + // i.e., text segments. The read/write/exec (data) segments would + // have been already added from core file segments. + for (lib_php = phbuf, i = 0; i < lib_ehdr->e_phnum; i++) { + if ((lib_php->p_type == PT_LOAD) && !(lib_php->p_flags & PF_W) && (lib_php->p_filesz != 0)) { + + uintptr_t target_vaddr = lib_php->p_vaddr + lib_base; + map_info *existing_map = core_lookup(ph, target_vaddr); - // we want to process only PT_LOAD segments that are not writable. - // i.e., text segments. The read/write/exec (data) segments would - // have been already added from core file segments. - for (lib_php = phbuf, i = 0; i < lib_ehdr->e_phnum; i++) { - if ((lib_php->p_type == PT_LOAD) && !(lib_php->p_flags & PF_W) && (lib_php->p_filesz != 0)) { - if (add_map_info(ph, lib_fd, lib_php->p_offset, lib_php->p_vaddr + lib_base, lib_php->p_filesz) == NULL) - goto err; + if (existing_map == NULL){ + if (add_map_info(ph, lib_fd, lib_php->p_offset, + target_vaddr, lib_php->p_filesz) == NULL) { + goto err; + } + } else { + if ((existing_map->memsz != page_size) && + (existing_map->fd != lib_fd) && + (existing_map->memsz != lib_php->p_filesz)){ + + print_debug("address conflict @ 0x%lx (size = %ld, flags = %d\n)", + target_vaddr, lib_php->p_filesz, lib_php->p_flags); + goto err; + } + + /* replace PT_LOAD segment with library segment */ + print_debug("overwrote with new address mapping (memsz %ld -> %ld)\n", + existing_map->memsz, lib_php->p_filesz); + + existing_map->fd = lib_fd; + existing_map->offset = lib_php->p_offset; + existing_map->memsz = lib_php->p_filesz; } - lib_php++; - } + } + + lib_php++; + } - free(phbuf); - return true; + free(phbuf); + return true; err: - free(phbuf); - return false; + free(phbuf); + return false; } // process segments from interpreter (ld.so or ld-linux.so) diff -r 510fbd28919c -r 1c3486050433 src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/classfile/javaClasses.cpp Fri Sep 27 15:43:03 2013 -0700 @@ -438,6 +438,29 @@ return true; } +bool java_lang_String::equals(oop str1, oop str2) { + assert(str1->klass() == SystemDictionary::String_klass(), + "must be java String"); + assert(str2->klass() == SystemDictionary::String_klass(), + "must be java String"); + typeArrayOop value1 = java_lang_String::value(str1); + int offset1 = java_lang_String::offset(str1); + int length1 = java_lang_String::length(str1); + typeArrayOop value2 = java_lang_String::value(str2); + int offset2 = java_lang_String::offset(str2); + int length2 = java_lang_String::length(str2); + + if (length1 != length2) { + return false; + } + for (int i = 0; i < length1; i++) { + if (value1->char_at(i + offset1) != value2->char_at(i + offset2)) { + return false; + } + } + return true; +} + void java_lang_String::print(Handle java_string, outputStream* st) { oop obj = java_string(); assert(obj->klass() == SystemDictionary::String_klass(), "must be java_string"); diff -r 510fbd28919c -r 1c3486050433 src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/classfile/javaClasses.hpp Fri Sep 27 15:43:03 2013 -0700 @@ -182,6 +182,7 @@ static unsigned int hash_string(oop java_string); static bool equals(oop java_string, jchar* chars, int len); + static bool equals(oop str1, oop str2); // Conversion between '.' and '/' formats static Handle externalize_classname(Handle java_string, TRAPS) { return char_converter(java_string, '/', '.', THREAD); } diff -r 510fbd28919c -r 1c3486050433 src/share/vm/classfile/symbolTable.cpp --- a/src/share/vm/classfile/symbolTable.cpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/classfile/symbolTable.cpp Fri Sep 27 15:43:03 2013 -0700 @@ -807,6 +807,8 @@ } } +// This verification is part of Universe::verify() and needs to be quick. +// See StringTable::verify_and_compare() below for exhaustive verification. void StringTable::verify() { for (int i = 0; i < the_table()->table_size(); ++i) { HashtableEntry* p = the_table()->bucket(i); @@ -825,6 +827,162 @@ the_table()->dump_table(st, "StringTable"); } +StringTable::VerifyRetTypes StringTable::compare_entries( + int bkt1, int e_cnt1, + HashtableEntry* e_ptr1, + int bkt2, int e_cnt2, + HashtableEntry* e_ptr2) { + // These entries are sanity checked by verify_and_compare_entries() + // before this function is called. + oop str1 = e_ptr1->literal(); + oop str2 = e_ptr2->literal(); + + if (str1 == str2) { + tty->print_cr("ERROR: identical oop values (0x" PTR_FORMAT ") " + "in entry @ bucket[%d][%d] and entry @ bucket[%d][%d]", + str1, bkt1, e_cnt1, bkt2, e_cnt2); + return _verify_fail_continue; + } + + if (java_lang_String::equals(str1, str2)) { + tty->print_cr("ERROR: identical String values in entry @ " + "bucket[%d][%d] and entry @ bucket[%d][%d]", + bkt1, e_cnt1, bkt2, e_cnt2); + return _verify_fail_continue; + } + + return _verify_pass; +} + +StringTable::VerifyRetTypes StringTable::verify_entry(int bkt, int e_cnt, + HashtableEntry* e_ptr, + StringTable::VerifyMesgModes mesg_mode) { + + VerifyRetTypes ret = _verify_pass; // be optimistic + + oop str = e_ptr->literal(); + if (str == NULL) { + if (mesg_mode == _verify_with_mesgs) { + tty->print_cr("ERROR: NULL oop value in entry @ bucket[%d][%d]", bkt, + e_cnt); + } + // NULL oop means no more verifications are possible + return _verify_fail_done; + } + + if (str->klass() != SystemDictionary::String_klass()) { + if (mesg_mode == _verify_with_mesgs) { + tty->print_cr("ERROR: oop is not a String in entry @ bucket[%d][%d]", + bkt, e_cnt); + } + // not a String means no more verifications are possible + return _verify_fail_done; + } + + unsigned int h = java_lang_String::hash_string(str); + if (e_ptr->hash() != h) { + if (mesg_mode == _verify_with_mesgs) { + tty->print_cr("ERROR: broken hash value in entry @ bucket[%d][%d], " + "bkt_hash=%d, str_hash=%d", bkt, e_cnt, e_ptr->hash(), h); + } + ret = _verify_fail_continue; + } + + if (the_table()->hash_to_index(h) != bkt) { + if (mesg_mode == _verify_with_mesgs) { + tty->print_cr("ERROR: wrong index value for entry @ bucket[%d][%d], " + "str_hash=%d, hash_to_index=%d", bkt, e_cnt, h, + the_table()->hash_to_index(h)); + } + ret = _verify_fail_continue; + } + + return ret; +} + +// See StringTable::verify() above for the quick verification that is +// part of Universe::verify(). This verification is exhaustive and +// reports on every issue that is found. StringTable::verify() only +// reports on the first issue that is found. +// +// StringTable::verify_entry() checks: +// - oop value != NULL (same as verify()) +// - oop value is a String +// - hash(String) == hash in entry (same as verify()) +// - index for hash == index of entry (same as verify()) +// +// StringTable::compare_entries() checks: +// - oops are unique across all entries +// - String values are unique across all entries +// +int StringTable::verify_and_compare_entries() { + assert(StringTable_lock->is_locked(), "sanity check"); + + int fail_cnt = 0; + + // first, verify all the entries individually: + for (int bkt = 0; bkt < the_table()->table_size(); bkt++) { + HashtableEntry* e_ptr = the_table()->bucket(bkt); + for (int e_cnt = 0; e_ptr != NULL; e_ptr = e_ptr->next(), e_cnt++) { + VerifyRetTypes ret = verify_entry(bkt, e_cnt, e_ptr, _verify_with_mesgs); + if (ret != _verify_pass) { + fail_cnt++; + } + } + } + + // Optimization: if the above check did not find any failures, then + // the comparison loop below does not need to call verify_entry() + // before calling compare_entries(). If there were failures, then we + // have to call verify_entry() to see if the entry can be passed to + // compare_entries() safely. When we call verify_entry() in the loop + // below, we do so quietly to void duplicate messages and we don't + // increment fail_cnt because the failures have already been counted. + bool need_entry_verify = (fail_cnt != 0); + + // second, verify all entries relative to each other: + for (int bkt1 = 0; bkt1 < the_table()->table_size(); bkt1++) { + HashtableEntry* e_ptr1 = the_table()->bucket(bkt1); + for (int e_cnt1 = 0; e_ptr1 != NULL; e_ptr1 = e_ptr1->next(), e_cnt1++) { + if (need_entry_verify) { + VerifyRetTypes ret = verify_entry(bkt1, e_cnt1, e_ptr1, + _verify_quietly); + if (ret == _verify_fail_done) { + // cannot use the current entry to compare against other entries + continue; + } + } + + for (int bkt2 = bkt1; bkt2 < the_table()->table_size(); bkt2++) { + HashtableEntry* e_ptr2 = the_table()->bucket(bkt2); + int e_cnt2; + for (e_cnt2 = 0; e_ptr2 != NULL; e_ptr2 = e_ptr2->next(), e_cnt2++) { + if (bkt1 == bkt2 && e_cnt2 <= e_cnt1) { + // skip the entries up to and including the one that + // we're comparing against + continue; + } + + if (need_entry_verify) { + VerifyRetTypes ret = verify_entry(bkt2, e_cnt2, e_ptr2, + _verify_quietly); + if (ret == _verify_fail_done) { + // cannot compare against this entry + continue; + } + } + + // compare two entries, report and count any failures: + if (compare_entries(bkt1, e_cnt1, e_ptr1, bkt2, e_cnt2, e_ptr2) + != _verify_pass) { + fail_cnt++; + } + } + } + } + } + return fail_cnt; +} // Create a new table and using alternate hash code, populate the new table // with the existing strings. Set flag to use the alternate hash code afterwards. diff -r 510fbd28919c -r 1c3486050433 src/share/vm/classfile/symbolTable.hpp --- a/src/share/vm/classfile/symbolTable.hpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/classfile/symbolTable.hpp Fri Sep 27 15:43:03 2013 -0700 @@ -311,6 +311,26 @@ static void verify(); static void dump(outputStream* st); + enum VerifyMesgModes { + _verify_quietly = 0, + _verify_with_mesgs = 1 + }; + + enum VerifyRetTypes { + _verify_pass = 0, + _verify_fail_continue = 1, + _verify_fail_done = 2 + }; + + static VerifyRetTypes compare_entries(int bkt1, int e_cnt1, + HashtableEntry* e_ptr1, + int bkt2, int e_cnt2, + HashtableEntry* e_ptr2); + static VerifyRetTypes verify_entry(int bkt, int e_cnt, + HashtableEntry* e_ptr, + VerifyMesgModes mesg_mode); + static int verify_and_compare_entries(); + // Sharing static void copy_buckets(char** top, char*end) { the_table()->Hashtable::copy_buckets(top, end); diff -r 510fbd28919c -r 1c3486050433 src/share/vm/memory/metaspaceShared.cpp --- a/src/share/vm/memory/metaspaceShared.cpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/memory/metaspaceShared.cpp Fri Sep 27 15:43:03 2013 -0700 @@ -103,9 +103,10 @@ if (k->oop_is_instance()) { InstanceKlass* ik = InstanceKlass::cast(k); for (int i = 0; i < ik->methods()->length(); i++) { - ResourceMark rm; Method* m = ik->methods()->at(i); - (new Fingerprinter(m))->fingerprint(); + Fingerprinter fp(m); + // The side effect of this call sets method's fingerprint field. + fp.fingerprint(); } } } diff -r 510fbd28919c -r 1c3486050433 src/share/vm/oops/constantPool.cpp --- a/src/share/vm/oops/constantPool.cpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/oops/constantPool.cpp Fri Sep 27 15:43:03 2013 -0700 @@ -108,16 +108,16 @@ void ConstantPool::initialize_resolved_references(ClassLoaderData* loader_data, intStack reference_map, int constant_pool_map_length, - TRAPS) { + TRAPS) { // Initialized the resolved object cache. int map_length = reference_map.length(); if (map_length > 0) { // Only need mapping back to constant pool entries. The map isn't used for - // invokedynamic resolved_reference entries. The constant pool cache index - // has the mapping back to both the constant pool and to the resolved - // reference index. + // invokedynamic resolved_reference entries. For invokedynamic entries, + // the constant pool cache index has the mapping back to both the constant + // pool and to the resolved reference index. if (constant_pool_map_length > 0) { - Array* om = MetadataFactory::new_array(loader_data, map_length, CHECK); + Array* om = MetadataFactory::new_array(loader_data, constant_pool_map_length, CHECK); for (int i = 0; i < constant_pool_map_length; i++) { int x = reference_map.at(i); @@ -182,16 +182,9 @@ int ConstantPool::cp_to_object_index(int cp_index) { // this is harder don't do this so much. - for (int i = 0; i< reference_map()->length(); i++) { - if (reference_map()->at(i) == cp_index) return i; - // Zero entry is divider between constant pool indices for strings, - // method handles and method types. After that the index is a constant - // pool cache index for invokedynamic. Stop when zero (which can never - // be a constant pool index) - if (reference_map()->at(i) == 0) break; - } - // We might not find the index. - return _no_index_sentinel; + int i = reference_map()->find(cp_index); + // We might not find the index for jsr292 call. + return (i < 0) ? _no_index_sentinel : i; } Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS) { @@ -840,8 +833,7 @@ // If the string has already been interned, this entry will be non-null oop str = this_oop->resolved_references()->obj_at(obj_index); if (str != NULL) return str; - - Symbol* sym = this_oop->unresolved_string_at(which); + Symbol* sym = this_oop->unresolved_string_at(which); str = StringTable::intern(sym, CHECK_(NULL)); this_oop->string_at_put(which, obj_index, str); assert(java_lang_String::is_instance(str), "must be string"); @@ -1619,9 +1611,11 @@ case JVM_CONSTANT_UnresolvedClassInError: case JVM_CONSTANT_StringIndex: case JVM_CONSTANT_MethodType: + case JVM_CONSTANT_MethodTypeInError: return 3; case JVM_CONSTANT_MethodHandle: + case JVM_CONSTANT_MethodHandleInError: return 4; //tag, ref_kind, ref_index case JVM_CONSTANT_Integer: @@ -1802,8 +1796,8 @@ case JVM_CONSTANT_MethodHandle: case JVM_CONSTANT_MethodHandleInError: { *bytes = JVM_CONSTANT_MethodHandle; - int kind = method_handle_ref_kind_at(idx); - idx1 = method_handle_index_at(idx); + int kind = method_handle_ref_kind_at_error_ok(idx); + idx1 = method_handle_index_at_error_ok(idx); *(bytes+1) = (unsigned char) kind; Bytes::put_Java_u2((address) (bytes+2), idx1); DBG(printf("JVM_CONSTANT_MethodHandle: %d %hd", kind, idx1)); @@ -1812,7 +1806,7 @@ case JVM_CONSTANT_MethodType: case JVM_CONSTANT_MethodTypeInError: { *bytes = JVM_CONSTANT_MethodType; - idx1 = method_type_index_at(idx); + idx1 = method_type_index_at_error_ok(idx); Bytes::put_Java_u2((address) (bytes+1), idx1); DBG(printf("JVM_CONSTANT_MethodType: %hd", idx1)); break; @@ -2000,12 +1994,12 @@ break; case JVM_CONSTANT_MethodHandle : case JVM_CONSTANT_MethodHandleInError : - st->print("ref_kind=%d", method_handle_ref_kind_at(index)); - st->print(" ref_index=%d", method_handle_index_at(index)); + st->print("ref_kind=%d", method_handle_ref_kind_at_error_ok(index)); + st->print(" ref_index=%d", method_handle_index_at_error_ok(index)); break; case JVM_CONSTANT_MethodType : case JVM_CONSTANT_MethodTypeInError : - st->print("signature_index=%d", method_type_index_at(index)); + st->print("signature_index=%d", method_type_index_at_error_ok(index)); break; case JVM_CONSTANT_InvokeDynamic : { diff -r 510fbd28919c -r 1c3486050433 src/share/vm/oops/constantPool.hpp --- a/src/share/vm/oops/constantPool.hpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/oops/constantPool.hpp Fri Sep 27 15:43:03 2013 -0700 @@ -231,7 +231,6 @@ static int cache_offset_in_bytes() { return offset_of(ConstantPool, _cache); } static int pool_holder_offset_in_bytes() { return offset_of(ConstantPool, _pool_holder); } static int resolved_references_offset_in_bytes() { return offset_of(ConstantPool, _resolved_references); } - static int reference_map_offset_in_bytes() { return offset_of(ConstantPool, _reference_map); } // Storing constants @@ -475,18 +474,42 @@ return *int_at_addr(which); } + private: + int method_handle_ref_kind_at(int which, bool error_ok) { + assert(tag_at(which).is_method_handle() || + (error_ok && tag_at(which).is_method_handle_in_error()), "Corrupted constant pool"); + return extract_low_short_from_int(*int_at_addr(which)); // mask out unwanted ref_index bits + } + int method_handle_index_at(int which, bool error_ok) { + assert(tag_at(which).is_method_handle() || + (error_ok && tag_at(which).is_method_handle_in_error()), "Corrupted constant pool"); + return extract_high_short_from_int(*int_at_addr(which)); // shift out unwanted ref_kind bits + } + int method_type_index_at(int which, bool error_ok) { + assert(tag_at(which).is_method_type() || + (error_ok && tag_at(which).is_method_type_in_error()), "Corrupted constant pool"); + return *int_at_addr(which); + } + public: int method_handle_ref_kind_at(int which) { - assert(tag_at(which).is_method_handle(), "Corrupted constant pool"); - return extract_low_short_from_int(*int_at_addr(which)); // mask out unwanted ref_index bits + return method_handle_ref_kind_at(which, false); + } + int method_handle_ref_kind_at_error_ok(int which) { + return method_handle_ref_kind_at(which, true); } int method_handle_index_at(int which) { - assert(tag_at(which).is_method_handle(), "Corrupted constant pool"); - return extract_high_short_from_int(*int_at_addr(which)); // shift out unwanted ref_kind bits + return method_handle_index_at(which, false); + } + int method_handle_index_at_error_ok(int which) { + return method_handle_index_at(which, true); } int method_type_index_at(int which) { - assert(tag_at(which).is_method_type(), "Corrupted constant pool"); - return *int_at_addr(which); + return method_type_index_at(which, false); } + int method_type_index_at_error_ok(int which) { + return method_type_index_at(which, true); + } + // Derived queries: Symbol* method_handle_name_ref_at(int which) { int member = method_handle_index_at(which); diff -r 510fbd28919c -r 1c3486050433 src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/oops/instanceKlass.cpp Fri Sep 27 15:43:03 2013 -0700 @@ -2769,24 +2769,17 @@ st->print(BULLET"field annotations: "); fields_annotations()->print_value_on(st); st->cr(); st->print(BULLET"field type annotations: "); fields_type_annotations()->print_value_on(st); st->cr(); { - ResourceMark rm; - // PreviousVersionInfo objects returned via PreviousVersionWalker - // contain a GrowableArray of handles. We have to clean up the - // GrowableArray _after_ the PreviousVersionWalker destructor - // has destroyed the handles. - { - bool have_pv = false; - PreviousVersionWalker pvw((InstanceKlass*)this); - for (PreviousVersionInfo * pv_info = pvw.next_previous_version(); - pv_info != NULL; pv_info = pvw.next_previous_version()) { - if (!have_pv) - st->print(BULLET"previous version: "); - have_pv = true; - pv_info->prev_constant_pool_handle()()->print_value_on(st); - } - if (have_pv) st->cr(); - } // pvw is cleaned up - } // rm is cleaned up + bool have_pv = false; + PreviousVersionWalker pvw(Thread::current(), (InstanceKlass*)this); + for (PreviousVersionNode * pv_node = pvw.next_previous_version(); + pv_node != NULL; pv_node = pvw.next_previous_version()) { + if (!have_pv) + st->print(BULLET"previous version: "); + have_pv = true; + pv_node->prev_constant_pool()->print_value_on(st); + } + if (have_pv) st->cr(); + } // pvw is cleaned up if (generic_signature() != NULL) { st->print(BULLET"generic signature: "); @@ -3317,34 +3310,34 @@ Array* old_methods = ikh->methods(); if (cp_ref->on_stack()) { - PreviousVersionNode * pv_node = NULL; - if (emcp_method_count == 0) { + PreviousVersionNode * pv_node = NULL; + if (emcp_method_count == 0) { // non-shared ConstantPool gets a reference - pv_node = new PreviousVersionNode(cp_ref, !cp_ref->is_shared(), NULL); - RC_TRACE(0x00000400, - ("add: all methods are obsolete; flushing any EMCP refs")); - } else { - int local_count = 0; + pv_node = new PreviousVersionNode(cp_ref, NULL); + RC_TRACE(0x00000400, + ("add: all methods are obsolete; flushing any EMCP refs")); + } else { + int local_count = 0; GrowableArray* method_refs = new (ResourceObj::C_HEAP, mtClass) - GrowableArray(emcp_method_count, true); - for (int i = 0; i < old_methods->length(); i++) { - if (emcp_methods->at(i)) { - // this old method is EMCP. Save it only if it's on the stack - Method* old_method = old_methods->at(i); - if (old_method->on_stack()) { - method_refs->append(old_method); + GrowableArray(emcp_method_count, true); + for (int i = 0; i < old_methods->length(); i++) { + if (emcp_methods->at(i)) { + // this old method is EMCP. Save it only if it's on the stack + Method* old_method = old_methods->at(i); + if (old_method->on_stack()) { + method_refs->append(old_method); + } + if (++local_count >= emcp_method_count) { + // no more EMCP methods so bail out now + break; } - if (++local_count >= emcp_method_count) { - // no more EMCP methods so bail out now - break; } } - } // non-shared ConstantPool gets a reference - pv_node = new PreviousVersionNode(cp_ref, !cp_ref->is_shared(), method_refs); + pv_node = new PreviousVersionNode(cp_ref, method_refs); } // append new previous version. - _previous_versions->append(pv_node); + _previous_versions->append(pv_node); } // Since the caller is the VMThread and we are at a safepoint, this @@ -3445,6 +3438,8 @@ return m; } } + // None found, return null for the caller to handle. + return NULL; } return m; } @@ -3461,10 +3456,9 @@ // Construct a PreviousVersionNode entry for the array hung off // the InstanceKlass. PreviousVersionNode::PreviousVersionNode(ConstantPool* prev_constant_pool, - bool prev_cp_is_weak, GrowableArray* prev_EMCP_methods) { + GrowableArray* prev_EMCP_methods) { _prev_constant_pool = prev_constant_pool; - _prev_cp_is_weak = prev_cp_is_weak; _prev_EMCP_methods = prev_EMCP_methods; } @@ -3480,99 +3474,38 @@ } } - -// Construct a PreviousVersionInfo entry -PreviousVersionInfo::PreviousVersionInfo(PreviousVersionNode *pv_node) { - _prev_constant_pool_handle = constantPoolHandle(); // NULL handle - _prev_EMCP_method_handles = NULL; - - ConstantPool* cp = pv_node->prev_constant_pool(); - assert(cp != NULL, "constant pool ref was unexpectedly cleared"); - if (cp == NULL) { - return; // robustness - } - - // make the ConstantPool* safe to return - _prev_constant_pool_handle = constantPoolHandle(cp); - - GrowableArray* method_refs = pv_node->prev_EMCP_methods(); - if (method_refs == NULL) { - // the InstanceKlass did not have any EMCP methods - return; - } - - _prev_EMCP_method_handles = new GrowableArray(10); - - int n_methods = method_refs->length(); - for (int i = 0; i < n_methods; i++) { - Method* method = method_refs->at(i); - assert (method != NULL, "method has been cleared"); - if (method == NULL) { - continue; // robustness - } - // make the Method* safe to return - _prev_EMCP_method_handles->append(methodHandle(method)); - } -} - - -// Destroy a PreviousVersionInfo -PreviousVersionInfo::~PreviousVersionInfo() { - // Since _prev_EMCP_method_handles is not C-heap allocated, we - // don't have to delete it. -} - - // Construct a helper for walking the previous versions array -PreviousVersionWalker::PreviousVersionWalker(InstanceKlass *ik) { +PreviousVersionWalker::PreviousVersionWalker(Thread* thread, InstanceKlass *ik) { + _thread = thread; _previous_versions = ik->previous_versions(); _current_index = 0; - // _hm needs no initialization _current_p = NULL; -} - - -// Destroy a PreviousVersionWalker -PreviousVersionWalker::~PreviousVersionWalker() { - // Delete the current info just in case the caller didn't walk to - // the end of the previous versions list. No harm if _current_p is - // already NULL. - delete _current_p; - - // When _hm is destroyed, all the Handles returned in - // PreviousVersionInfo objects will be destroyed. - // Also, after this destructor is finished it will be - // safe to delete the GrowableArray allocated in the - // PreviousVersionInfo objects. + _current_constant_pool_handle = constantPoolHandle(thread, ik->constants()); } // Return the interesting information for the next previous version // of the klass. Returns NULL if there are no more previous versions. -PreviousVersionInfo* PreviousVersionWalker::next_previous_version() { +PreviousVersionNode* PreviousVersionWalker::next_previous_version() { if (_previous_versions == NULL) { // no previous versions so nothing to return return NULL; } - delete _current_p; // cleanup the previous info for the caller - _current_p = NULL; // reset to NULL so we don't delete same object twice + _current_p = NULL; // reset to NULL + _current_constant_pool_handle = NULL; int length = _previous_versions->length(); while (_current_index < length) { PreviousVersionNode * pv_node = _previous_versions->at(_current_index++); - PreviousVersionInfo * pv_info = new (ResourceObj::C_HEAP, mtClass) - PreviousVersionInfo(pv_node); - - constantPoolHandle cp_h = pv_info->prev_constant_pool_handle(); - assert (!cp_h.is_null(), "null cp found in previous version"); - - // The caller will need to delete pv_info when they are done with it. - _current_p = pv_info; - return pv_info; + + // Save a handle to the constant pool for this previous version, + // which keeps all the methods from being deallocated. + _current_constant_pool_handle = constantPoolHandle(_thread, pv_node->prev_constant_pool()); + _current_p = pv_node; + return pv_node; } - // all of the underlying nodes' info has been deleted return NULL; } // end next_previous_version() diff -r 510fbd28919c -r 1c3486050433 src/share/vm/oops/instanceKlass.hpp --- a/src/share/vm/oops/instanceKlass.hpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/oops/instanceKlass.hpp Fri Sep 27 15:43:03 2013 -0700 @@ -1126,21 +1126,11 @@ // A collection point for interesting information about the previous -// version(s) of an InstanceKlass. This class uses weak references to -// the information so that the information may be collected as needed -// by the system. If the information is shared, then a regular -// reference must be used because a weak reference would be seen as -// collectible. A GrowableArray of PreviousVersionNodes is attached -// to the InstanceKlass as needed. See PreviousVersionWalker below. +// version(s) of an InstanceKlass. A GrowableArray of PreviousVersionNodes +// is attached to the InstanceKlass as needed. See PreviousVersionWalker below. class PreviousVersionNode : public CHeapObj { private: - // A shared ConstantPool is never collected so we'll always have - // a reference to it so we can update items in the cache. We'll - // have a weak reference to a non-shared ConstantPool until all - // of the methods (EMCP or obsolete) have been collected; the - // non-shared ConstantPool becomes collectible at that point. - ConstantPool* _prev_constant_pool; // regular or weak reference - bool _prev_cp_is_weak; // true if not a shared ConstantPool + ConstantPool* _prev_constant_pool; // If the previous version of the InstanceKlass doesn't have any // EMCP methods, then _prev_EMCP_methods will be NULL. If all the @@ -1149,8 +1139,8 @@ GrowableArray* _prev_EMCP_methods; public: - PreviousVersionNode(ConstantPool* prev_constant_pool, bool prev_cp_is_weak, - GrowableArray* prev_EMCP_methods); + PreviousVersionNode(ConstantPool* prev_constant_pool, + GrowableArray* prev_EMCP_methods); ~PreviousVersionNode(); ConstantPool* prev_constant_pool() const { return _prev_constant_pool; @@ -1161,59 +1151,26 @@ }; -// A Handle-ized version of PreviousVersionNode. -class PreviousVersionInfo : public ResourceObj { - private: - constantPoolHandle _prev_constant_pool_handle; - // If the previous version of the InstanceKlass doesn't have any - // EMCP methods, then _prev_EMCP_methods will be NULL. Since the - // methods cannot be collected while we hold a handle, - // _prev_EMCP_methods should never have a length of zero. - GrowableArray* _prev_EMCP_method_handles; - -public: - PreviousVersionInfo(PreviousVersionNode *pv_node); - ~PreviousVersionInfo(); - constantPoolHandle prev_constant_pool_handle() const { - return _prev_constant_pool_handle; - } - GrowableArray* prev_EMCP_method_handles() const { - return _prev_EMCP_method_handles; - } -}; - - -// Helper object for walking previous versions. This helper cleans up -// the Handles that it allocates when the helper object is destroyed. -// The PreviousVersionInfo object returned by next_previous_version() -// is only valid until a subsequent call to next_previous_version() or -// the helper object is destroyed. +// Helper object for walking previous versions. class PreviousVersionWalker : public StackObj { private: + Thread* _thread; GrowableArray* _previous_versions; int _current_index; - // Fields for cleaning up when we are done walking the previous versions: - // A HandleMark for the PreviousVersionInfo handles: - HandleMark _hm; + + // A pointer to the current node object so we can handle the deletes. + PreviousVersionNode* _current_p; - // It would be nice to have a ResourceMark field in this helper also, - // but the ResourceMark code says to be careful to delete handles held - // in GrowableArrays _before_ deleting the GrowableArray. Since we - // can't guarantee the order in which the fields are destroyed, we - // have to let the creator of the PreviousVersionWalker object do - // the right thing. Also, adding a ResourceMark here causes an - // include loop. - - // A pointer to the current info object so we can handle the deletes. - PreviousVersionInfo * _current_p; + // The constant pool handle keeps all the methods in this class from being + // deallocated from the metaspace during class unloading. + constantPoolHandle _current_constant_pool_handle; public: - PreviousVersionWalker(InstanceKlass *ik); - ~PreviousVersionWalker(); + PreviousVersionWalker(Thread* thread, InstanceKlass *ik); // Return the interesting information for the next previous version // of the klass. Returns NULL if there are no more previous versions. - PreviousVersionInfo* next_previous_version(); + PreviousVersionNode* next_previous_version(); }; diff -r 510fbd28919c -r 1c3486050433 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/prims/jvm.cpp Fri Sep 27 15:43:03 2013 -0700 @@ -1835,16 +1835,27 @@ } JVM_END -JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, jboolean publicOnly)) -{ - JVMWrapper("JVM_GetClassDeclaredMethods"); +static bool select_method(methodHandle method, bool want_constructor) { + if (want_constructor) { + return (method->is_initializer() && !method->is_static()); + } else { + return (!method->is_initializer() && !method->is_overpass()); + } +} + +static jobjectArray get_class_declared_methods_helper( + JNIEnv *env, + jclass ofClass, jboolean publicOnly, + bool want_constructor, + Klass* klass, TRAPS) { + JvmtiVMObjectAllocEventCollector oam; // Exclude primitive types and array types if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass)) || java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->oop_is_array()) { // Return empty array - oop res = oopFactory::new_objArray(SystemDictionary::reflect_Method_klass(), 0, CHECK_NULL); + oop res = oopFactory::new_objArray(klass, 0, CHECK_NULL); return (jobjectArray) JNIHandles::make_local(env, res); } @@ -1855,87 +1866,67 @@ Array* methods = k->methods(); int methods_length = methods->length(); + + // Save original method_idnum in case of redefinition, which can change + // the idnum of obsolete methods. The new method will have the same idnum + // but if we refresh the methods array, the counts will be wrong. + ResourceMark rm(THREAD); + GrowableArray* idnums = new GrowableArray(methods_length); int num_methods = 0; - int i; - for (i = 0; i < methods_length; i++) { + for (int i = 0; i < methods_length; i++) { methodHandle method(THREAD, methods->at(i)); - if (!method->is_initializer() && !method->is_overpass()) { + if (select_method(method, want_constructor)) { if (!publicOnly || method->is_public()) { + idnums->push(method->method_idnum()); ++num_methods; } } } // Allocate result - objArrayOop r = oopFactory::new_objArray(SystemDictionary::reflect_Method_klass(), num_methods, CHECK_NULL); + objArrayOop r = oopFactory::new_objArray(klass, num_methods, CHECK_NULL); objArrayHandle result (THREAD, r); - int out_idx = 0; - for (i = 0; i < methods_length; i++) { - methodHandle method(THREAD, methods->at(i)); - if (!method->is_initializer() && !method->is_overpass()) { - if (!publicOnly || method->is_public()) { - oop m = Reflection::new_method(method, UseNewReflection, false, CHECK_NULL); - result->obj_at_put(out_idx, m); - ++out_idx; + // Now just put the methods that we selected above, but go by their idnum + // in case of redefinition. The methods can be redefined at any safepoint, + // so above when allocating the oop array and below when creating reflect + // objects. + for (int i = 0; i < num_methods; i++) { + methodHandle method(THREAD, k->method_with_idnum(idnums->at(i))); + if (method.is_null()) { + // Method may have been deleted and seems this API can handle null + // Otherwise should probably put a method that throws NSME + result->obj_at_put(i, NULL); + } else { + oop m; + if (want_constructor) { + m = Reflection::new_constructor(method, CHECK_NULL); + } else { + m = Reflection::new_method(method, UseNewReflection, false, CHECK_NULL); } + result->obj_at_put(i, m); } } - assert(out_idx == num_methods, "just checking"); + return (jobjectArray) JNIHandles::make_local(env, result()); } + +JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, jboolean publicOnly)) +{ + JVMWrapper("JVM_GetClassDeclaredMethods"); + return get_class_declared_methods_helper(env, ofClass, publicOnly, + /*want_constructor*/ false, + SystemDictionary::reflect_Method_klass(), THREAD); +} JVM_END JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly)) { JVMWrapper("JVM_GetClassDeclaredConstructors"); - JvmtiVMObjectAllocEventCollector oam; - - // Exclude primitive types and array types - if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass)) - || java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->oop_is_array()) { - // Return empty array - oop res = oopFactory::new_objArray(SystemDictionary::reflect_Constructor_klass(), 0 , CHECK_NULL); - return (jobjectArray) JNIHandles::make_local(env, res); - } - - instanceKlassHandle k(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))); - - // Ensure class is linked - k->link_class(CHECK_NULL); - - Array* methods = k->methods(); - int methods_length = methods->length(); - int num_constructors = 0; - - int i; - for (i = 0; i < methods_length; i++) { - methodHandle method(THREAD, methods->at(i)); - if (method->is_initializer() && !method->is_static()) { - if (!publicOnly || method->is_public()) { - ++num_constructors; - } - } - } - - // Allocate result - objArrayOop r = oopFactory::new_objArray(SystemDictionary::reflect_Constructor_klass(), num_constructors, CHECK_NULL); - objArrayHandle result(THREAD, r); - - int out_idx = 0; - for (i = 0; i < methods_length; i++) { - methodHandle method(THREAD, methods->at(i)); - if (method->is_initializer() && !method->is_static()) { - if (!publicOnly || method->is_public()) { - oop m = Reflection::new_constructor(method, CHECK_NULL); - result->obj_at_put(out_idx, m); - ++out_idx; - } - } - } - assert(out_idx == num_constructors, "just checking"); - return (jobjectArray) JNIHandles::make_local(env, result()); + return get_class_declared_methods_helper(env, ofClass, publicOnly, + /*want_constructor*/ true, + SystemDictionary::reflect_Constructor_klass(), THREAD); } JVM_END diff -r 510fbd28919c -r 1c3486050433 src/share/vm/prims/jvmtiEnvBase.hpp --- a/src/share/vm/prims/jvmtiEnvBase.hpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/prims/jvmtiEnvBase.hpp Fri Sep 27 15:43:03 2013 -0700 @@ -406,7 +406,11 @@ VMOp_Type type() const { return VMOp_GetCurrentContendedMonitor; } jvmtiError result() { return _result; } void doit() { - _result = ((JvmtiEnvBase *)_env)->get_current_contended_monitor(_calling_thread,_java_thread,_owned_monitor_ptr); + _result = JVMTI_ERROR_THREAD_NOT_ALIVE; + if (Threads::includes(_java_thread) && !_java_thread->is_exiting() && + _java_thread->threadObj() != NULL) { + _result = ((JvmtiEnvBase *)_env)->get_current_contended_monitor(_calling_thread,_java_thread,_owned_monitor_ptr); + } } }; diff -r 510fbd28919c -r 1c3486050433 src/share/vm/prims/jvmtiImpl.cpp --- a/src/share/vm/prims/jvmtiImpl.cpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/prims/jvmtiImpl.cpp Fri Sep 27 15:43:03 2013 -0700 @@ -273,59 +273,49 @@ // add/remove breakpoint to/from versions of the method that // are EMCP. Directly or transitively obsolete methods are - // not saved in the PreviousVersionInfo. + // not saved in the PreviousVersionNodes. Thread *thread = Thread::current(); instanceKlassHandle ikh = instanceKlassHandle(thread, _method->method_holder()); Symbol* m_name = _method->name(); Symbol* m_signature = _method->signature(); - { - ResourceMark rm(thread); - // PreviousVersionInfo objects returned via PreviousVersionWalker - // contain a GrowableArray of handles. We have to clean up the - // GrowableArray _after_ the PreviousVersionWalker destructor - // has destroyed the handles. - { - // search previous versions if they exist - PreviousVersionWalker pvw((InstanceKlass *)ikh()); - for (PreviousVersionInfo * pv_info = pvw.next_previous_version(); - pv_info != NULL; pv_info = pvw.next_previous_version()) { - GrowableArray* methods = - pv_info->prev_EMCP_method_handles(); + // search previous versions if they exist + PreviousVersionWalker pvw(thread, (InstanceKlass *)ikh()); + for (PreviousVersionNode * pv_node = pvw.next_previous_version(); + pv_node != NULL; pv_node = pvw.next_previous_version()) { + GrowableArray* methods = pv_node->prev_EMCP_methods(); - if (methods == NULL) { - // We have run into a PreviousVersion generation where - // all methods were made obsolete during that generation's - // RedefineClasses() operation. At the time of that - // operation, all EMCP methods were flushed so we don't - // have to go back any further. - // - // A NULL methods array is different than an empty methods - // array. We cannot infer any optimizations about older - // generations from an empty methods array for the current - // generation. - break; - } + if (methods == NULL) { + // We have run into a PreviousVersion generation where + // all methods were made obsolete during that generation's + // RedefineClasses() operation. At the time of that + // operation, all EMCP methods were flushed so we don't + // have to go back any further. + // + // A NULL methods array is different than an empty methods + // array. We cannot infer any optimizations about older + // generations from an empty methods array for the current + // generation. + break; + } - for (int i = methods->length() - 1; i >= 0; i--) { - methodHandle method = methods->at(i); - // obsolete methods that are running are not deleted from - // previous version array, but they are skipped here. - if (!method->is_obsolete() && - method->name() == m_name && - method->signature() == m_signature) { - RC_TRACE(0x00000800, ("%sing breakpoint in %s(%s)", - meth_act == &Method::set_breakpoint ? "sett" : "clear", - method->name()->as_C_string(), - method->signature()->as_C_string())); + for (int i = methods->length() - 1; i >= 0; i--) { + Method* method = methods->at(i); + // obsolete methods that are running are not deleted from + // previous version array, but they are skipped here. + if (!method->is_obsolete() && + method->name() == m_name && + method->signature() == m_signature) { + RC_TRACE(0x00000800, ("%sing breakpoint in %s(%s)", + meth_act == &Method::set_breakpoint ? "sett" : "clear", + method->name()->as_C_string(), + method->signature()->as_C_string())); - ((Method*)method()->*meth_act)(_bci); - break; - } - } + (method->*meth_act)(_bci); + break; } - } // pvw is cleaned up - } // rm is cleaned up + } + } } void JvmtiBreakpoint::set() { diff -r 510fbd28919c -r 1c3486050433 src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Sep 27 15:43:03 2013 -0700 @@ -2807,28 +2807,20 @@ &trace_name_printed); } } - { - ResourceMark rm(_thread); - // PreviousVersionInfo objects returned via PreviousVersionWalker - // contain a GrowableArray of handles. We have to clean up the - // GrowableArray _after_ the PreviousVersionWalker destructor - // has destroyed the handles. - { - // the previous versions' constant pool caches may need adjustment - PreviousVersionWalker pvw(ik); - for (PreviousVersionInfo * pv_info = pvw.next_previous_version(); - pv_info != NULL; pv_info = pvw.next_previous_version()) { - other_cp = pv_info->prev_constant_pool_handle(); - cp_cache = other_cp->cache(); - if (cp_cache != NULL) { - cp_cache->adjust_method_entries(_matching_old_methods, - _matching_new_methods, - _matching_methods_length, - &trace_name_printed); - } - } - } // pvw is cleaned up - } // rm is cleaned up + + // the previous versions' constant pool caches may need adjustment + PreviousVersionWalker pvw(_thread, ik); + for (PreviousVersionNode * pv_node = pvw.next_previous_version(); + pv_node != NULL; pv_node = pvw.next_previous_version()) { + other_cp = pv_node->prev_constant_pool(); + cp_cache = other_cp->cache(); + if (cp_cache != NULL) { + cp_cache->adjust_method_entries(_matching_old_methods, + _matching_new_methods, + _matching_methods_length, + &trace_name_printed); + } + } } } @@ -2942,10 +2934,9 @@ // obsolete methods need a unique idnum u2 num = InstanceKlass::cast(_the_class_oop)->next_method_idnum(); if (num != ConstMethod::UNSET_IDNUM) { -// u2 old_num = old_method->method_idnum(); old_method->set_method_idnum(num); -// TO DO: attach obsolete annotations to obsolete method's new idnum } + // With tracing we try not to "yack" too much. The position of // this trace assumes there are fewer obsolete methods than // EMCP methods. diff -r 510fbd28919c -r 1c3486050433 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/runtime/arguments.cpp Fri Sep 27 15:43:03 2013 -0700 @@ -1100,6 +1100,7 @@ } } +#if defined(COMPILER2) || defined(_LP64) || !INCLUDE_CDS // Conflict: required to use shared spaces (-Xshare:on), but // incompatible command line options were chosen. @@ -1112,6 +1113,7 @@ FLAG_SET_DEFAULT(UseSharedSpaces, false); } } +#endif void Arguments::set_tiered_flags() { // With tiered, set default policy to AdvancedThresholdPolicy, which is 3. @@ -1523,16 +1525,18 @@ FLAG_SET_ERGO(bool, UseParallelGC, true); } } - // Shared spaces work fine with other GCs but causes bytecode rewriting - // to be disabled, which hurts interpreter performance and decreases - // server performance. On server class machines, keep the default - // off unless it is asked for. Future work: either add bytecode rewriting - // at link time, or rewrite bytecodes in non-shared methods. - if (!DumpSharedSpaces && !RequireSharedSpaces && - (FLAG_IS_DEFAULT(UseSharedSpaces) || !UseSharedSpaces)) { - no_shared_spaces(); - } } +#ifdef COMPILER2 + // Shared spaces work fine with other GCs but causes bytecode rewriting + // to be disabled, which hurts interpreter performance and decreases + // server performance. When -server is specified, keep the default off + // unless it is asked for. Future work: either add bytecode rewriting + // at link time, or rewrite bytecodes in non-shared methods. + if (!DumpSharedSpaces && !RequireSharedSpaces && + (FLAG_IS_DEFAULT(UseSharedSpaces) || !UseSharedSpaces)) { + no_shared_spaces(); + } +#endif set_conservative_max_heap_alignment(); @@ -2446,21 +2450,6 @@ return result; } - if (AggressiveOpts) { - // Insert alt-rt.jar between user-specified bootclasspath - // prefix and the default bootclasspath. os::set_boot_path() - // uses meta_index_dir as the default bootclasspath directory. - const char* altclasses_jar = "alt-rt.jar"; - size_t altclasses_path_len = strlen(get_meta_index_dir()) + 1 + - strlen(altclasses_jar); - char* altclasses_path = NEW_C_HEAP_ARRAY(char, altclasses_path_len, mtInternal); - strcpy(altclasses_path, get_meta_index_dir()); - strcat(altclasses_path, altclasses_jar); - scp.add_suffix_to_prefix(altclasses_path); - scp_assembly_required = true; - FREE_C_HEAP_ARRAY(char, altclasses_path, mtInternal); - } - // Parse _JAVA_OPTIONS environment variable (if present) (mimics classic VM) result = parse_java_options_environment_variable(&scp, &scp_assembly_required); if (result != JNI_OK) { diff -r 510fbd28919c -r 1c3486050433 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/runtime/globals.hpp Fri Sep 27 15:43:03 2013 -0700 @@ -2567,6 +2567,9 @@ product(bool, PrintStringTableStatistics, false, \ "print statistics about the StringTable and SymbolTable") \ \ + diagnostic(bool, VerifyStringTableAtExit, false, \ + "verify StringTable contents at exit") \ + \ notproduct(bool, PrintSymbolTableSizeHistogram, false, \ "print histogram of the symbol table") \ \ diff -r 510fbd28919c -r 1c3486050433 src/share/vm/runtime/handles.hpp --- a/src/share/vm/runtime/handles.hpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/runtime/handles.hpp Fri Sep 27 15:43:03 2013 -0700 @@ -136,7 +136,7 @@ // Specific Handles for different oop types #define DEF_METADATA_HANDLE(name, type) \ class name##Handle; \ - class name##Handle { \ + class name##Handle : public StackObj { \ type* _value; \ Thread* _thread; \ protected: \ @@ -175,7 +175,7 @@ // Writing this class explicitly, since DEF_METADATA_HANDLE(klass) doesn't // provide the necessary Klass* <-> Klass* conversions. This Klass // could be removed when we don't have the Klass* typedef anymore. -class KlassHandle { +class KlassHandle : public StackObj { Klass* _value; protected: Klass* obj() const { return _value; } diff -r 510fbd28919c -r 1c3486050433 src/share/vm/runtime/handles.inline.hpp --- a/src/share/vm/runtime/handles.inline.hpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/runtime/handles.inline.hpp Fri Sep 27 15:43:03 2013 -0700 @@ -79,6 +79,7 @@ } else { \ _thread = Thread::current(); \ } \ + assert (_thread->is_in_stack((address)this), "not on stack?"); \ _thread->metadata_handles()->push((Metadata*)_value); \ } else { \ _thread = NULL; \ @@ -95,6 +96,7 @@ } else { \ _thread = Thread::current(); \ } \ + assert (_thread->is_in_stack((address)this), "not on stack?"); \ _thread->metadata_handles()->push((Metadata*)_value); \ } else { \ _thread = NULL; \ diff -r 510fbd28919c -r 1c3486050433 src/share/vm/runtime/java.cpp --- a/src/share/vm/runtime/java.cpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/runtime/java.cpp Fri Sep 27 15:43:03 2013 -0700 @@ -544,6 +544,19 @@ // it will run into trouble when system destroys static variables. MemTracker::shutdown(MemTracker::NMT_normal); + if (VerifyStringTableAtExit) { + int fail_cnt = 0; + { + MutexLocker ml(StringTable_lock); + fail_cnt = StringTable::verify_and_compare_entries(); + } + + if (fail_cnt != 0) { + tty->print_cr("ERROR: fail_cnt=%d", fail_cnt); + guarantee(fail_cnt == 0, "unexpected StringTable verification failures"); + } + } + #undef BEFORE_EXIT_NOT_RUN #undef BEFORE_EXIT_RUNNING #undef BEFORE_EXIT_DONE diff -r 510fbd28919c -r 1c3486050433 src/share/vm/services/attachListener.cpp --- a/src/share/vm/services/attachListener.cpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/services/attachListener.cpp Fri Sep 27 15:43:03 2013 -0700 @@ -470,7 +470,17 @@ vmSymbols::threadgroup_string_void_signature(), thread_group, string, - CHECK); + THREAD); + + if (HAS_PENDING_EXCEPTION) { + tty->print_cr("Exception in VM (AttachListener::init) : "); + java_lang_Throwable::print(PENDING_EXCEPTION, tty); + tty->cr(); + + CLEAR_PENDING_EXCEPTION; + + return; + } KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass()); JavaCalls::call_special(&result, @@ -479,7 +489,17 @@ vmSymbols::add_method_name(), vmSymbols::thread_void_signature(), thread_oop, // ARG 1 - CHECK); + THREAD); + + if (HAS_PENDING_EXCEPTION) { + tty->print_cr("Exception in VM (AttachListener::init) : "); + java_lang_Throwable::print(PENDING_EXCEPTION, tty); + tty->cr(); + + CLEAR_PENDING_EXCEPTION; + + return; + } { MutexLocker mu(Threads_lock); JavaThread* listener_thread = new JavaThread(&attach_listener_thread_entry); diff -r 510fbd28919c -r 1c3486050433 src/share/vm/services/diagnosticArgument.cpp --- a/src/share/vm/services/diagnosticArgument.cpp Fri Sep 27 10:50:55 2013 +0200 +++ b/src/share/vm/services/diagnosticArgument.cpp Fri Sep 27 15:43:03 2013 -0700 @@ -61,7 +61,7 @@ } void GenDCmdArgument::to_string(char* c, char* buf, size_t len) { - jio_snprintf(buf, len, "%s", c); + jio_snprintf(buf, len, "%s", (c != NULL) ? c : ""); } void GenDCmdArgument::to_string(StringArrayArgument* f, char* buf, size_t len) { diff -r 510fbd28919c -r 1c3486050433 test/runtime/CDSCompressedKPtrs/XShareAuto.java --- a/test/runtime/CDSCompressedKPtrs/XShareAuto.java Fri Sep 27 10:50:55 2013 +0200 +++ b/test/runtime/CDSCompressedKPtrs/XShareAuto.java Fri Sep 27 15:43:03 2013 -0700 @@ -33,16 +33,9 @@ public class XShareAuto { public static void main(String[] args) throws Exception { - if (!Platform.is64bit()) { - System.out.println("ObjectAlignmentInBytes for CDS is only " + - "supported on 64bit platforms; this plaform is " + - System.getProperty("sun.arch.data.model")); - System.out.println("Skipping the test"); - return; - } ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", - "-Xshare:dump"); + "-server", "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Loading classes to share"); output.shouldHaveExitValue(0);