diff -r 2cb5d5f6d5e5 src/share/vm/ci/ciEnv.cpp --- a/src/share/vm/ci/ciEnv.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/ci/ciEnv.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -32,6 +32,7 @@ #include "ci/ciNullObject.hpp" #include "ci/ciReplay.hpp" #include "ci/ciUtilities.hpp" +#include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/scopeDesc.hpp" @@ -274,7 +275,8 @@ ciInstance* ciEnv::ClassCastException_in ciInstance* ciEnv::the_null_string() { if (_the_null_string == NULL) { VM_ENTRY_MARK; - _the_null_string = get_object(Universe::the_null_string())->as_instance(); + oop s = StringTable::intern("null", CATCH); + _the_null_string = get_object(s)->as_instance(); } return _the_null_string; } @@ -282,7 +284,8 @@ ciInstance* ciEnv::the_null_string() { ciInstance* ciEnv::the_min_jint_string() { if (_the_min_jint_string == NULL) { VM_ENTRY_MARK; - _the_min_jint_string = get_object(Universe::the_min_jint_string())->as_instance(); + oop s = StringTable::intern("-2147483648", CATCH); + _the_min_jint_string = get_object(s)->as_instance(); } return _the_min_jint_string; } diff -r 2cb5d5f6d5e5 src/share/vm/ci/ciObject.cpp --- a/src/share/vm/ci/ciObject.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/ci/ciObject.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -192,14 +192,16 @@ bool ciObject::should_be_constant() { return handle() == NULL; } -// ------------------------------------------------------------------ -// ciObject::should_be_constant() +/** + * Set some flags for this object. + */ void ciObject::init_flags_from(oop x) { int flags = 0; if (x != NULL) { - assert(Universe::heap()->is_in_reserved(x), "must be"); - if (x->is_scavengable()) + assert(Universe::is_in_reserved_heap_or_shared(x), err_msg("must be in heap or shared: " PTR_FORMAT, x)); + if (x->is_scavengable()) { flags |= SCAVENGABLE_FLAG; + } } _ident |= flags; } diff -r 2cb5d5f6d5e5 src/share/vm/ci/ciObjectFactory.cpp --- a/src/share/vm/ci/ciObjectFactory.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/ci/ciObjectFactory.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -236,7 +236,7 @@ void ciObjectFactory::remove_symbols() { ciObject* ciObjectFactory::get(oop key) { ASSERT_IN_VM; - assert(key == NULL || Universe::heap()->is_in_reserved(key), "must be"); + assert(Universe::is_in_reserved_heap_or_shared_or_null(key), "must be"); NonPermObject* &bucket = find_non_perm(key); if (bucket != NULL) { @@ -249,7 +249,7 @@ ciObject* ciObjectFactory::get(oop key) ciObject* new_object = create_new_object(keyHandle()); assert(keyHandle() == new_object->get_oop(), "must be properly recorded"); init_ident_of(new_object); - assert(Universe::heap()->is_in_reserved(new_object->get_oop()), "must be"); + assert(Universe::is_in_reserved_heap_or_shared(new_object->get_oop()), "must be"); // Not a perm-space object. insert_non_perm(bucket, keyHandle(), new_object); @@ -666,7 +666,7 @@ static ciObjectFactory::NonPermObject* e // If there is no entry in the cache corresponding to this oop, return // the null tail of the bucket into which the oop should be inserted. ciObjectFactory::NonPermObject* &ciObjectFactory::find_non_perm(oop key) { - assert(Universe::heap()->is_in_reserved_or_null(key), "must be"); + assert(Universe::is_in_reserved_heap_or_shared_or_null(key), "must be"); ciMetadata* klass = get_metadata(key->klass()); NonPermObject* *bp = &_non_perm_bucket[(unsigned) klass->hash() % NON_PERM_BUCKETS]; for (NonPermObject* p; (p = (*bp)) != NULL; bp = &p->next()) { @@ -694,7 +694,7 @@ inline ciObjectFactory::NonPermObject::N // // Insert a ciObject into the non-perm table. void ciObjectFactory::insert_non_perm(ciObjectFactory::NonPermObject* &where, oop key, ciObject* obj) { - assert(Universe::heap()->is_in_reserved_or_null(key), "must be"); + assert(Universe::is_in_reserved_heap_or_shared_or_null(key), "must be"); assert(&where != &emptyBucket, "must not try to fill empty bucket"); NonPermObject* p = new (arena()) NonPermObject(where, key, obj); assert(where == p && is_equal(p, key) && p->object() == obj, "entry must match"); diff -r 2cb5d5f6d5e5 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/classfile/classFileParser.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -275,7 +275,7 @@ void ClassFileParser::parse_constant_poo } unsigned int hash; - Symbol* result = SymbolTable::lookup_only((char*)utf8_buffer, utf8_length, hash); + Symbol* result = SymbolTable::the_table()->lookup_only((char*)utf8_buffer, utf8_length, hash); if (result == NULL) { names[names_count] = (char*)utf8_buffer; lengths[names_count] = utf8_length; diff -r 2cb5d5f6d5e5 src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/classfile/javaClasses.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/altHashing.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/vmSymbols.hpp" #include "code/debugInfo.hpp" @@ -158,32 +159,46 @@ void java_lang_String::compute_offsets() initialized = true; } -Handle java_lang_String::basic_create(int length, TRAPS) { +Handle java_lang_String::basic_create(int length, bool in_metaspace, TRAPS) { assert(initialized, "Must be initialized"); // Create the String object first, so there's a chance that the String // and the char array it points to end up in the same cache line. - oop obj; - obj = InstanceKlass::cast(SystemDictionary::String_klass())->allocate_instance(CHECK_NH); - - // Create the char array. The String object must be handlized here - // because GC can happen as a result of the allocation attempt. - Handle h_obj(THREAD, obj); - typeArrayOop buffer; - buffer = oopFactory::new_charArray(length, CHECK_NH); - - // Point the String at the char array - obj = h_obj(); - set_value(obj, buffer); - // No need to zero the offset, allocation zero'ed the entire String object - assert(offset(obj) == 0, "initial String offset should be zero"); -//set_offset(obj, 0); - set_count(obj, length); - - return h_obj; -} - -Handle java_lang_String::create_from_unicode(jchar* unicode, int length, TRAPS) { - Handle h_obj = basic_create(length, CHECK_NH); + InstanceKlass* ik = InstanceKlass::cast(SystemDictionary::String_klass()); + + if (in_metaspace) { + ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); + oop obj = ik->allocate_metaspace_instance(loader_data, CHECK_NH); + typeArrayOop buffer = oopFactory::new_metaspace_charArray(loader_data, length, CHECK_NH); + + // Point the String at the char array + // Note: We use a raw store here because the object isn't in the heap. + set_value_raw(obj, buffer); + // No need to zero the offset, allocation zero'ed the entire String object + assert(offset(obj) == 0, "initial String offset should be zero"); + set_count(obj, length); + + return Handle(THREAD, obj); + } else { + oop obj = ik->allocate_instance(CHECK_NH); + + // Create the char array. The String object must be handlized here + // because GC can happen as a result of the allocation attempt. + Handle h_obj(THREAD, obj); + typeArrayOop buffer = oopFactory::new_charArray(length, CHECK_NH); + + // Point the String at the char array + obj = h_obj(); + set_value(obj, buffer); + // No need to zero the offset, allocation zero'ed the entire String object + assert(offset(obj) == 0, "initial String offset should be zero"); + set_count(obj, length); + + return h_obj; + } +} + +Handle java_lang_String::create_from_unicode(jchar* unicode, int length, bool in_metaspace, TRAPS) { + Handle h_obj = basic_create(length, in_metaspace, CHECK_NH); typeArrayOop buffer = value(h_obj()); for (int index = 0; index < length; index++) { buffer->char_at_put(index, unicode[index]); @@ -191,6 +206,21 @@ Handle java_lang_String::create_from_uni return h_obj; } +Handle java_lang_String::create_from_unicode(jchar* unicode, int length, TRAPS) { + return create_from_unicode(unicode, length, false, CHECK_NH); +} + +Handle java_lang_String::create_intern_from_unicode(jchar* unicode, int length, TRAPS) { + const bool in_metaspace = DumpSharedSpaces; + Handle obj = create_from_unicode(unicode, length, in_metaspace, CHECK_NH); + if (in_metaspace) { + // Let's calculate the hashes since we have time... + set_hash(obj(), hash_code(obj())); + (void) obj->slow_identity_hash(); + } + return obj; +} + oop java_lang_String::create_oop_from_unicode(jchar* unicode, int length, TRAPS) { Handle h_obj = create_from_unicode(unicode, length, CHECK_0); return h_obj(); @@ -201,7 +231,7 @@ Handle java_lang_String::create_from_str return Handle(); } int length = UTF8::unicode_length(utf8_str); - Handle h_obj = basic_create(length, CHECK_NH); + Handle h_obj = basic_create(length, false, CHECK_NH); if (length > 0) { UTF8::convert_to_unicode(utf8_str, value(h_obj())->char_at_addr(0), length); } @@ -215,7 +245,7 @@ oop java_lang_String::create_oop_from_st Handle java_lang_String::create_from_symbol(Symbol* symbol, TRAPS) { int length = UTF8::unicode_length((char*)symbol->bytes(), symbol->utf8_length()); - Handle h_obj = basic_create(length, CHECK_NH); + Handle h_obj = basic_create(length, false, CHECK_NH); if (length > 0) { UTF8::convert_to_unicode((char*)symbol->bytes(), value(h_obj())->char_at_addr(0), length); } @@ -299,7 +329,7 @@ Handle java_lang_String::char_converter( // Create new UNICODE buffer. Must handlize value because GC // may happen during String and char array creation. typeArrayHandle h_value(THREAD, value); - Handle string = basic_create(length, CHECK_NH); + Handle string = basic_create(length, false, CHECK_NH); typeArrayOop from_buffer = h_value(); typeArrayOop to_buffer = java_lang_String::value(string()); diff -r 2cb5d5f6d5e5 src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/classfile/javaClasses.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -59,30 +59,41 @@ class java_lang_String : AllStatic { static bool initialized; - static Handle basic_create(int length, TRAPS); + static Handle basic_create(int length, bool in_metaspace, TRAPS); - static void set_value( oop string, typeArrayOop buffer) { + static void set_value(oop string, typeArrayOop buffer) { assert(initialized, "Must be initialized"); - string->obj_field_put(value_offset, (oop)buffer); + string->obj_field_put(value_offset, (oop)buffer); + } + static void set_value_raw(oop string, typeArrayOop buffer) { + assert(initialized, "Must be initialized"); + assert(DumpSharedSpaces, "only when we dump shared spaces"); + string->obj_field_put_raw(value_offset, (oop)buffer); } static void set_offset(oop string, int offset) { - assert(initialized, "Must be initialized"); - if (offset_offset > 0) { + if (has_offset_field()) { string->int_field_put(offset_offset, offset); } } - static void set_count( oop string, int count) { - assert(initialized, "Must be initialized"); - if (count_offset > 0) { - string->int_field_put(count_offset, count); + static void set_count(oop string, int count) { + if (has_count_field()) { + string->int_field_put(count_offset, count); } } + static void set_hash(oop string, int hash) { + if (has_hash_field()) { + string->int_field_put(hash_offset, hash); + } + } + + static Handle create_from_unicode(jchar* unicode, int length, bool in_metaspace, TRAPS); public: static void compute_offsets(); // Instance creation static Handle create_from_unicode(jchar* unicode, int len, TRAPS); + static Handle create_intern_from_unicode(jchar* unicode, int length, TRAPS); static oop create_oop_from_unicode(jchar* unicode, int len, TRAPS); static Handle create_from_str(const char* utf8_str, TRAPS); static oop create_oop_from_str(const char* utf8_str, TRAPS); diff -r 2cb5d5f6d5e5 src/share/vm/classfile/stringTable.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/stringTable.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -0,0 +1,364 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/altHashing.hpp" +#include "classfile/javaClasses.hpp" +#include "classfile/stringTable.hpp" +#include "classfile/systemDictionary.hpp" +#include "gc_interface/collectedHeap.inline.hpp" +#include "memory/allocation.inline.hpp" +#include "memory/filemap.hpp" +#include "memory/gcLocker.inline.hpp" +#include "oops/oop.inline.hpp" +#include "oops/oop.inline2.hpp" +#include "runtime/mutexLocker.hpp" +#include "utilities/hashtable.inline.hpp" + +// -------------------------------------------------------------------------- + +#ifdef ASSERT +class StableMemoryChecker : public StackObj { + enum { _bufsize = wordSize*4 }; + + address _region; + jint _size; + u1 _save_buf[_bufsize]; + + int sample(u1* save_buf) { + if (_size <= _bufsize) { + memcpy(save_buf, _region, _size); + return _size; + } else { + // copy head and tail + memcpy(&save_buf[0], _region, _bufsize/2); + memcpy(&save_buf[_bufsize/2], _region + _size - _bufsize/2, _bufsize/2); + return (_bufsize/2)*2; + } + } + + public: + StableMemoryChecker(const void* region, jint size) { + _region = (address) region; + _size = size; + sample(_save_buf); + } + + bool verify() { + u1 check_buf[sizeof(_save_buf)]; + int check_size = sample(check_buf); + return (0 == memcmp(_save_buf, check_buf, check_size)); + } + + void set_region(const void* region) { _region = (address) region; } +}; +#endif + +// -------------------------------------------------------------------------- +StringTable* StringTable::_table = NULL; +StringTable* StringTable::_shared_table = NULL; + +bool StringTable::_needs_rehashing = false; + +// Pick hashing algorithm +unsigned int StringTable::hash_string(const jchar* s, int len) { + return use_alternate_hashcode() ? AltHashing::murmur3_32(seed(), s, len) : + java_lang_String::hash_code(s, len); +} + +/** + * Add a string to either the shared table or the dynamic table. Strings + * are only added to the shared table if we are dumping shared spaces. + */ +oop StringTable::basic_add(Handle string, jchar* name, int len, TRAPS) { + const unsigned int hashValue = hash_string(name, len); + if (DumpSharedSpaces && shared_table() != NULL) { + return shared_table()->basic_add(string, name, len, hashValue, CHECK_NULL); + } + return the_table()->basic_add(string, name, len, hashValue, CHECK_NULL); +} + +/** + * Add a string to this table. + */ +oop StringTable::basic_add(Handle string, jchar* name, int len, unsigned int hashValue, TRAPS) { + const int index = hash_to_index(hashValue); + return basic_add(index, string, name, len, hashValue, CHECK_NULL); +} + +/** + * This method eventually adds the string to the hashtable. + */ +oop StringTable::basic_add(int index_arg, Handle string, jchar* name, + int len, unsigned int hashValue_arg, TRAPS) { + assert(java_lang_String::equals(string(), name, len), + "string must be properly initialized"); + // Cannot hit a safepoint in this function because the "this" pointer can move. + No_Safepoint_Verifier nsv; + + // Check if the symbol table has been rehashed, if so, need to recalculate + // the hash value and index before second lookup. + unsigned int hashValue; + int index; + if (use_alternate_hashcode()) { + hashValue = hash_string(name, len); + index = hash_to_index(hashValue); + } else { + hashValue = hashValue_arg; + index = index_arg; + } + + // Since look-up was done lock-free, we need to check if another + // thread beat us in the race to insert the symbol. + + oop test = lookup(index, name, len, hashValue); + if (test != NULL) { + // Entry already added + return test; + } + + HashtableEntry* entry = new_entry(hashValue, string()); + add_entry(index, entry); + return string(); +} + +/** + * Lookup up a string symbol in the string table. + */ +oop StringTable::lookup(Symbol* symbol) { + ResourceMark rm; + int length; + jchar* chars = symbol->as_unicode(length); + return lookup(chars, length); +} + +/** + * This is the main lookup method which needs to do the lookup in both + * tables, the shared and dynamic one. + */ +oop StringTable::lookup(jchar* name, int len) { + const unsigned int hash = hash_string(name, len); + + // First try to find the symbol in the shared table if available: + if (shared_table() != NULL) { + oop s = shared_table()->lookup(name, len, hash); + if (s != NULL) { + return s; + } + } + + // Now try the dynamic table: + return the_table()->lookup(name, len, hash); +} + +/** + * Lookup a method in this string table. + */ +oop StringTable::lookup(jchar* name, int len, unsigned int hash) { + const int index = hash_to_index(hash); + return lookup(index, name, len, hash); +} + +/** + * This is the actual string table lookup function. It only operates on + * one table. + */ +oop StringTable::lookup(int index, jchar* name, int len, unsigned int hash) { + int count = 0; + for (HashtableEntry* l = bucket(index); l != NULL; l = l->next()) { + count++; + if (l->hash() == hash) { + if (java_lang_String::equals(l->literal(), name, len)) { + return l->literal(); + } + } + } + // If the bucket size is too deep check if this hash code is insufficient. + if (count >= BasicHashtable::rehash_count && !needs_rehashing()) { + _needs_rehashing = check_rehash_table(count); + } + return NULL; +} + + +oop StringTable::intern(Symbol* symbol, TRAPS) { + if (symbol == NULL) return NULL; + ResourceMark rm(THREAD); + int length; + jchar* chars = symbol->as_unicode(length); + Handle string; + oop result = intern(string, chars, length, CHECK_NULL); + return result; +} + + +oop StringTable::intern(oop string, TRAPS) { + if (string == NULL) return NULL; + ResourceMark rm(THREAD); + int length; + Handle h_string (THREAD, string); + jchar* chars = java_lang_String::as_unicode_string(string, length, CHECK_NULL); + oop result = intern(h_string, chars, length, CHECK_NULL); + return result; +} + + +oop StringTable::intern(const char* utf8_string, TRAPS) { + if (utf8_string == NULL) return NULL; + ResourceMark rm(THREAD); + int length = UTF8::unicode_length(utf8_string); + jchar* chars = NEW_RESOURCE_ARRAY(jchar, length); + UTF8::convert_to_unicode(utf8_string, chars, length); + Handle string; + oop result = intern(string, chars, length, CHECK_NULL); + return result; +} + +/** + * This is the main string intern function and decides into which string table + * the string is interned. + */ +oop StringTable::intern(Handle string_or_null, jchar* name, int len, TRAPS) { + oop found_string = lookup(name, len); + + // Found + if (found_string != NULL) { + return found_string; + } + + DEBUG_ONLY(StableMemoryChecker smc(name, len * sizeof(name[0]))); + assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(), + "proposed name of symbol must be stable"); + + Handle string; + // try to reuse the string if possible + if (!string_or_null.is_null()) { + string = string_or_null; + } else { + string = java_lang_String::create_intern_from_unicode(name, len, CHECK_NULL); + } + + // Grab the StringTable_lock before getting the_table() because it could + // change at safepoint. + MutexLocker ml(StringTable_lock, THREAD); + + // Otherwise, add to symbol to table + return basic_add(string, name, len, CHECK_NULL); +} + +void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { + // Readers of the table are unlocked, so we should only be removing + // entries at a safepoint. + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + for (int i = 0; i < the_table()->table_size(); ++i) { + HashtableEntry** p = the_table()->bucket_addr(i); + HashtableEntry* entry = the_table()->bucket(i); + while (entry != NULL) { + assert(!entry->is_shared(), "CDS not used for the StringTable"); + + if (is_alive->do_object_b(entry->literal())) { + if (f != NULL) { + f->do_oop((oop*)entry->literal_addr()); + } + p = entry->next_addr(); + } else { + *p = entry->next(); + the_table()->free_entry(entry); + } + entry = *p; + } + } +} + +void StringTable::oops_do(OopClosure* f) { + for (int i = 0; i < the_table()->table_size(); ++i) { + HashtableEntry* entry = the_table()->bucket(i); + while (entry != NULL) { + assert(!entry->is_shared(), "CDS not used for the StringTable"); + + f->do_oop((oop*)entry->literal_addr()); + + entry = entry->next(); + } + } +} + + +/** + * Verifies the entries in this string table. + */ +void StringTable::verify_impl() { + for (int i = 0; i < table_size(); i++) { + HashtableEntry* p = bucket(i); + for ( ; p != NULL; p = p->next()) { + oop s = p->literal(); + guarantee(s != NULL, "interned string is NULL"); + unsigned int h = java_lang_String::hash_string(s); + guarantee(p->hash() == h, "broken hash in string table entry"); + guarantee(hash_to_index(h) == i, "wrong index in string table"); + } + } +} + +/** + * Static method to verify the string tables. + */ +void StringTable::verify() { + if (shared_table() != NULL) { + shared_table()->verify_impl(); + } + the_table()->verify_impl(); +} + +/** + * Static method to dump statistics of the string tables. + */ +void StringTable::dump(outputStream* st) { + if (shared_table() != NULL) { + shared_table()->dump_table(st, "Shared StringTable"); + } + if (the_table() != NULL) { + the_table()->dump_table(st, "Dynamic StringTable"); + } +} + + +// 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. +void StringTable::rehash_table() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + // This should never happen with -Xshare:dump but it might in testing mode. + if (DumpSharedSpaces) return; + StringTable* new_table = new StringTable(); + + // Rehash the table + the_table()->move_to(new_table); + + // Delete the table and buckets (entries are reused in new table). + delete _table; + // Don't check if we need rehashing until the table gets unbalanced again. + // Then rehash with a new global seed. + _needs_rehashing = false; + _table = new_table; +} diff -r 2cb5d5f6d5e5 src/share/vm/classfile/stringTable.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/stringTable.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_CLASSFILE_STRINGTABLE_HPP +#define SHARE_VM_CLASSFILE_STRINGTABLE_HPP + +#include "memory/allocation.inline.hpp" +#include "oops/symbol.hpp" +#include "utilities/hashtable.hpp" + +class SharedStringTable; + +/** + * The table of all interned strings. + */ +class StringTable : public Hashtable { + friend class VMStructs; + +private: + // The string table + static StringTable* _table; + static StringTable* _shared_table; + + // Set if one bucket is out of balance due to hash algorithm deficiency + static bool _needs_rehashing; + + // The string table + static StringTable* the_table() { return _table; } + static StringTable* shared_table() { return _shared_table; } + + static oop intern(Handle string_or_null, jchar* chars, int length, TRAPS); + + static oop basic_add(Handle string_or_null, jchar* name, int len, TRAPS); + oop basic_add(Handle string_or_null, jchar* name, int len, + unsigned int hashValue, TRAPS); + oop basic_add(int index, Handle string_or_null, jchar* name, int len, + unsigned int hashValue, TRAPS); + + oop lookup(jchar* chars, int length, unsigned int hashValue); + oop lookup(int index, jchar* chars, int length, unsigned int hashValue); + + StringTable() : Hashtable((int)StringTableSize, + sizeof (HashtableEntry)) {} + + StringTable(HashtableBucket* t, int number_of_entries) + : Hashtable((int)StringTableSize, sizeof (HashtableEntry), t, + number_of_entries) {} + +public: + // Size of one bucket in the string table. Used when checking for rollover. + static uint bucket_size() { return sizeof(HashtableBucket); } + + static void create_table() { + assert(_table == NULL, "One string table allowed."); + _table = new StringTable(); + } + + static void create_shared_table() { + assert(_shared_table == NULL, "One shared string table allowed."); + assert(UseG1GC, "shared interned strings only supported with G1"); + _shared_table = new StringTable(); + } + + static void create_shared_table(HashtableBucket* t, int length, int number_of_entries) { + assert(_shared_table == NULL, "One shared string table allowed."); + assert(UseG1GC, "shared interned strings only supported with G1"); + //assert(length == symbol_table_size * sizeof(HashtableBucket), "bad shared symbol size."); + _shared_table = new StringTable(t, number_of_entries); + } + + // GC support + // Delete pointers to otherwise-unreachable objects. + static void unlink_or_oops_do(BoolObjectClosure* cl, OopClosure* f); + static void unlink(BoolObjectClosure* cl) { + unlink_or_oops_do(cl, NULL); + } + + // Invoke "f->do_oop" on the locations of all oops in the table. + static void oops_do(OopClosure* f); + + // Hashing algorithm, used as the hash value used by the + // StringTable for bucket selection and comparison (stored in the + // HashtableEntry structures). This is used in the String.intern() method. + static unsigned int hash_string(const jchar* s, int len); + + // Internal test. + static void test_alt_hash() PRODUCT_RETURN; + + // Probing + static oop lookup(Symbol* symbol); + static oop lookup(jchar* chars, int length); + + // Interning + static oop intern(Symbol* symbol, TRAPS); + static oop intern(oop string, TRAPS); + static oop intern(const char *utf8_string, TRAPS); + + // Debugging +private: + void verify_impl(); + +public: + static void verify(); + static void dump(outputStream* st); + + // Sharing. These only operate on the shared table. + static void copy_buckets(char** top, char* end) { + shared_table()->Hashtable::copy_buckets(top, end); + } + static void copy_table(char** top, char* end) { + shared_table()->Hashtable::copy_table(top, end); + } + static void reverse(void* boundary = NULL) { + shared_table()->Hashtable::reverse(boundary); + } + + // Rehash the symbol table if it gets out of balance + static void rehash_table(); + static bool needs_rehashing() { return _needs_rehashing; } +}; + +#endif // SHARE_VM_CLASSFILE_STRINGTABLE_HPP diff -r 2cb5d5f6d5e5 src/share/vm/classfile/symbolTable.cpp --- a/src/share/vm/classfile/symbolTable.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/classfile/symbolTable.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -552,262 +552,3 @@ void SymbolTable::print() { } } #endif // PRODUCT - -// -------------------------------------------------------------------------- - -#ifdef ASSERT -class StableMemoryChecker : public StackObj { - enum { _bufsize = wordSize*4 }; - - address _region; - jint _size; - u1 _save_buf[_bufsize]; - - int sample(u1* save_buf) { - if (_size <= _bufsize) { - memcpy(save_buf, _region, _size); - return _size; - } else { - // copy head and tail - memcpy(&save_buf[0], _region, _bufsize/2); - memcpy(&save_buf[_bufsize/2], _region + _size - _bufsize/2, _bufsize/2); - return (_bufsize/2)*2; - } - } - - public: - StableMemoryChecker(const void* region, jint size) { - _region = (address) region; - _size = size; - sample(_save_buf); - } - - bool verify() { - u1 check_buf[sizeof(_save_buf)]; - int check_size = sample(check_buf); - return (0 == memcmp(_save_buf, check_buf, check_size)); - } - - void set_region(const void* region) { _region = (address) region; } -}; -#endif - - -// -------------------------------------------------------------------------- -StringTable* StringTable::_the_table = NULL; - -bool StringTable::_needs_rehashing = false; - -// Pick hashing algorithm -unsigned int StringTable::hash_string(const jchar* s, int len) { - return use_alternate_hashcode() ? AltHashing::murmur3_32(seed(), s, len) : - java_lang_String::hash_code(s, len); -} - -oop StringTable::lookup(int index, jchar* name, - int len, unsigned int hash) { - int count = 0; - for (HashtableEntry* l = bucket(index); l != NULL; l = l->next()) { - count++; - if (l->hash() == hash) { - if (java_lang_String::equals(l->literal(), name, len)) { - return l->literal(); - } - } - } - // If the bucket size is too deep check if this hash code is insufficient. - if (count >= BasicHashtable::rehash_count && !needs_rehashing()) { - _needs_rehashing = check_rehash_table(count); - } - return NULL; -} - - -oop StringTable::basic_add(int index_arg, Handle string, jchar* name, - int len, unsigned int hashValue_arg, TRAPS) { - - assert(java_lang_String::equals(string(), name, len), - "string must be properly initialized"); - // Cannot hit a safepoint in this function because the "this" pointer can move. - No_Safepoint_Verifier nsv; - - // Check if the symbol table has been rehashed, if so, need to recalculate - // the hash value and index before second lookup. - unsigned int hashValue; - int index; - if (use_alternate_hashcode()) { - hashValue = hash_string(name, len); - index = hash_to_index(hashValue); - } else { - hashValue = hashValue_arg; - index = index_arg; - } - - // Since look-up was done lock-free, we need to check if another - // thread beat us in the race to insert the symbol. - - oop test = lookup(index, name, len, hashValue); // calls lookup(u1*, int) - if (test != NULL) { - // Entry already added - return test; - } - - HashtableEntry* entry = new_entry(hashValue, string()); - add_entry(index, entry); - return string(); -} - - -oop StringTable::lookup(Symbol* symbol) { - ResourceMark rm; - int length; - jchar* chars = symbol->as_unicode(length); - return lookup(chars, length); -} - - -oop StringTable::lookup(jchar* name, int len) { - unsigned int hash = hash_string(name, len); - int index = the_table()->hash_to_index(hash); - return the_table()->lookup(index, name, len, hash); -} - - -oop StringTable::intern(Handle string_or_null, jchar* name, - int len, TRAPS) { - unsigned int hashValue = hash_string(name, len); - int index = the_table()->hash_to_index(hashValue); - oop found_string = the_table()->lookup(index, name, len, hashValue); - - // Found - if (found_string != NULL) return found_string; - - debug_only(StableMemoryChecker smc(name, len * sizeof(name[0]))); - assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(), - "proposed name of symbol must be stable"); - - Handle string; - // try to reuse the string if possible - if (!string_or_null.is_null()) { - string = string_or_null; - } else { - string = java_lang_String::create_from_unicode(name, len, CHECK_NULL); - } - - // Grab the StringTable_lock before getting the_table() because it could - // change at safepoint. - MutexLocker ml(StringTable_lock, THREAD); - - // Otherwise, add to symbol to table - return the_table()->basic_add(index, string, name, len, - hashValue, CHECK_NULL); -} - -oop StringTable::intern(Symbol* symbol, TRAPS) { - if (symbol == NULL) return NULL; - ResourceMark rm(THREAD); - int length; - jchar* chars = symbol->as_unicode(length); - Handle string; - oop result = intern(string, chars, length, CHECK_NULL); - return result; -} - - -oop StringTable::intern(oop string, TRAPS) -{ - if (string == NULL) return NULL; - ResourceMark rm(THREAD); - int length; - Handle h_string (THREAD, string); - jchar* chars = java_lang_String::as_unicode_string(string, length, CHECK_NULL); - oop result = intern(h_string, chars, length, CHECK_NULL); - return result; -} - - -oop StringTable::intern(const char* utf8_string, TRAPS) { - if (utf8_string == NULL) return NULL; - ResourceMark rm(THREAD); - int length = UTF8::unicode_length(utf8_string); - jchar* chars = NEW_RESOURCE_ARRAY(jchar, length); - UTF8::convert_to_unicode(utf8_string, chars, length); - Handle string; - oop result = intern(string, chars, length, CHECK_NULL); - return result; -} - -void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { - // Readers of the table are unlocked, so we should only be removing - // entries at a safepoint. - assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); - for (int i = 0; i < the_table()->table_size(); ++i) { - HashtableEntry** p = the_table()->bucket_addr(i); - HashtableEntry* entry = the_table()->bucket(i); - while (entry != NULL) { - assert(!entry->is_shared(), "CDS not used for the StringTable"); - - if (is_alive->do_object_b(entry->literal())) { - if (f != NULL) { - f->do_oop((oop*)entry->literal_addr()); - } - p = entry->next_addr(); - } else { - *p = entry->next(); - the_table()->free_entry(entry); - } - entry = *p; - } - } -} - -void StringTable::oops_do(OopClosure* f) { - for (int i = 0; i < the_table()->table_size(); ++i) { - HashtableEntry* entry = the_table()->bucket(i); - while (entry != NULL) { - assert(!entry->is_shared(), "CDS not used for the StringTable"); - - f->do_oop((oop*)entry->literal_addr()); - - entry = entry->next(); - } - } -} - -void StringTable::verify() { - for (int i = 0; i < the_table()->table_size(); ++i) { - HashtableEntry* p = the_table()->bucket(i); - for ( ; p != NULL; p = p->next()) { - oop s = p->literal(); - guarantee(s != NULL, "interned string is NULL"); - unsigned int h = java_lang_String::hash_string(s); - guarantee(p->hash() == h, "broken hash in string table entry"); - guarantee(the_table()->hash_to_index(h) == i, - "wrong index in string table"); - } - } -} - -void StringTable::dump(outputStream* st) { - the_table()->dump_table(st, "StringTable"); -} - - -// 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. -void StringTable::rehash_table() { - assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); - // This should never happen with -Xshare:dump but it might in testing mode. - if (DumpSharedSpaces) return; - StringTable* new_table = new StringTable(); - - // Rehash the table - the_table()->move_to(new_table); - - // Delete the table and buckets (entries are reused in new table). - delete _the_table; - // Don't check if we need rehashing until the table gets unbalanced again. - // Then rehash with a new global seed. - _needs_rehashing = false; - _the_table = new_table; -} diff -r 2cb5d5f6d5e5 src/share/vm/classfile/symbolTable.hpp --- a/src/share/vm/classfile/symbolTable.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/classfile/symbolTable.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -221,10 +221,10 @@ public: static void dump(outputStream* st); // Sharing - static void copy_buckets(char** top, char*end) { + static void copy_buckets(char** top, char* end) { the_table()->Hashtable::copy_buckets(top, end); } - static void copy_table(char** top, char*end) { + static void copy_table(char** top, char* end) { the_table()->Hashtable::copy_table(top, end); } static void reverse(void* boundary = NULL) { @@ -236,84 +236,4 @@ public: static bool needs_rehashing() { return _needs_rehashing; } }; -class StringTable : public Hashtable { - friend class VMStructs; - -private: - // The string table - static StringTable* _the_table; - - // Set if one bucket is out of balance due to hash algorithm deficiency - static bool _needs_rehashing; - - static oop intern(Handle string_or_null, jchar* chars, int length, TRAPS); - oop basic_add(int index, Handle string_or_null, jchar* name, int len, - unsigned int hashValue, TRAPS); - - oop lookup(int index, jchar* chars, int length, unsigned int hashValue); - - StringTable() : Hashtable((int)StringTableSize, - sizeof (HashtableEntry)) {} - - StringTable(HashtableBucket* t, int number_of_entries) - : Hashtable((int)StringTableSize, sizeof (HashtableEntry), t, - number_of_entries) {} -public: - // The string table - static StringTable* the_table() { return _the_table; } - - // Size of one bucket in the string table. Used when checking for rollover. - static uint bucket_size() { return sizeof(HashtableBucket); } - - static void create_table() { - assert(_the_table == NULL, "One string table allowed."); - _the_table = new StringTable(); - } - - // GC support - // Delete pointers to otherwise-unreachable objects. - static void unlink_or_oops_do(BoolObjectClosure* cl, OopClosure* f); - static void unlink(BoolObjectClosure* cl) { - unlink_or_oops_do(cl, NULL); - } - - // Invoke "f->do_oop" on the locations of all oops in the table. - static void oops_do(OopClosure* f); - - // Hashing algorithm, used as the hash value used by the - // StringTable for bucket selection and comparison (stored in the - // HashtableEntry structures). This is used in the String.intern() method. - static unsigned int hash_string(const jchar* s, int len); - - // Internal test. - static void test_alt_hash() PRODUCT_RETURN; - - // Probing - static oop lookup(Symbol* symbol); - static oop lookup(jchar* chars, int length); - - // Interning - static oop intern(Symbol* symbol, TRAPS); - static oop intern(oop string, TRAPS); - static oop intern(const char *utf8_string, TRAPS); - - // Debugging - static void verify(); - static void dump(outputStream* st); - - // Sharing - static void copy_buckets(char** top, char*end) { - the_table()->Hashtable::copy_buckets(top, end); - } - static void copy_table(char** top, char*end) { - the_table()->Hashtable::copy_table(top, end); - } - static void reverse() { - the_table()->Hashtable::reverse(); - } - - // Rehash the symbol table if it gets out of balance - static void rehash_table(); - static bool needs_rehashing() { return _needs_rehashing; } -}; #endif // SHARE_VM_CLASSFILE_SYMBOLTABLE_HPP diff -r 2cb5d5f6d5e5 src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/classfile/systemDictionary.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -29,6 +29,7 @@ #include "classfile/loaderConstraints.hpp" #include "classfile/placeholders.hpp" #include "classfile/resolutionErrors.hpp" +#include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "compiler/compileBroker.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/code/debugInfo.cpp --- a/src/share/vm/code/debugInfo.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/code/debugInfo.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -202,9 +202,8 @@ void ConstantDoubleValue::print_on(outpu // ConstantOopWriteValue void ConstantOopWriteValue::write_on(DebugInfoWriteStream* stream) { - assert(JNIHandles::resolve(value()) == NULL || - Universe::heap()->is_in_reserved(JNIHandles::resolve(value())), - "Should be in heap"); + assert(Universe::is_in_reserved_heap_or_shared_or_null(JNIHandles::resolve(value())), + err_msg_res("should be in heap: " PTR_FORMAT, JNIHandles::resolve(value()))); stream->write_int(CONSTANT_OOP_CODE); stream->write_handle(value()); } @@ -218,8 +217,8 @@ void ConstantOopWriteValue::print_on(out ConstantOopReadValue::ConstantOopReadValue(DebugInfoReadStream* stream) { _value = Handle(stream->read_oop()); - assert(_value() == NULL || - Universe::heap()->is_in_reserved(_value()), "Should be in heap"); + assert(Universe::is_in_reserved_heap_or_shared_or_null(_value()), + err_msg_res("should be in heap: " PTR_FORMAT, _value())); } void ConstantOopReadValue::write_on(DebugInfoWriteStream* stream) { diff -r 2cb5d5f6d5e5 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/code/nmethod.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -1479,12 +1479,15 @@ void nmethod::flush_dependencies(BoolObj } -// If this oop is not live, the nmethod can be unloaded. +/** + * If the oop is not alive, this nmethod can be unloaded. + */ bool nmethod::can_unload(BoolObjectClosure* is_alive, oop* root, bool unloading_occurred) { assert(root != NULL, "just checking"); oop obj = *root; - if (obj == NULL || is_alive->do_object_b(obj)) { - return false; + // Shared objects are always alive. + if (obj == NULL || obj->is_shared() || is_alive->do_object_b(obj)) { + return false; } // If ScavengeRootsInCode is true, an nmethod might be unloaded @@ -1942,7 +1945,8 @@ public: { NOT_PRODUCT(_print_nm = NULL); } bool detected_scavenge_root() { return _detected_scavenge_root; } virtual void do_oop(oop* p) { - if ((*p) != NULL && (*p)->is_scavengable()) { + oop o = *p; + if (o != NULL && o->is_scavengable()) { NOT_PRODUCT(maybe_print(p)); _detected_scavenge_root = true; } @@ -2451,14 +2455,17 @@ public: DebugScavengeRoot(nmethod* nm) : _nm(nm), _ok(true) { } bool ok() { return _ok; } virtual void do_oop(oop* p) { - if ((*p) == NULL || !(*p)->is_scavengable()) return; + oop o = *p; + if (o == NULL || !o->is_scavengable()) { + return; + } if (_ok) { _nm->print_nmethod(true); _ok = false; } tty->print_cr("*** scavengable oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)", - (intptr_t)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm)); - (*p)->print(); + (intptr_t)o, (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm)); + o->print(); } virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } }; diff -r 2cb5d5f6d5e5 src/share/vm/compiler/oopMap.cpp --- a/src/share/vm/compiler/oopMap.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/compiler/oopMap.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -425,7 +425,7 @@ void OopMapSet::all_do(const frame *fr, } #ifdef ASSERT if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) || - !Universe::heap()->is_in_or_null(*loc)) { + !Universe::is_in_heap_or_shared_or_null(*loc)) { tty->print_cr("# Found non oop pointer. Dumping state at failure"); // try to dump out some helpful debugging information trace_codeblob_maps(fr, reg_map); @@ -434,7 +434,7 @@ void OopMapSet::all_do(const frame *fr, omv.reg()->print(); tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc); // do the real assert. - assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer"); + assert(Universe::is_in_heap_or_shared_or_null(*loc), err_msg("found non oop pointer: " PTR_FORMAT, *loc)); } #endif // ASSERT oop_fn->do_oop(loc); @@ -632,7 +632,7 @@ intptr_t value_of_loc(oop *pointer) { re void DerivedPointerTable::add(oop *derived_loc, oop *base_loc) { - assert(Universe::heap()->is_in_or_null(*base_loc), "not an oop"); + assert(Universe::is_in_heap_or_shared_or_null(*base_loc), err_msg("not an oop: " PTR_FORMAT, *base_loc)); assert(derived_loc != base_loc, "Base and derived in same location"); if (_active) { assert(*derived_loc != (oop)base_loc, "location already added"); @@ -667,7 +667,7 @@ void DerivedPointerTable::update_pointer intptr_t offset = entry->offset(); // The derived oop was setup to point to location of base oop base = **(oop**)derived_loc; - assert(Universe::heap()->is_in_or_null(base), "must be an oop"); + assert(Universe::is_in_heap_or_shared_or_null(base), err_msg("must be an oop: " PTR_FORMAT, base)); *derived_loc = (oop)(((address)base) + offset); assert(value_of_loc(derived_loc) - value_of_loc(&base) == offset, "sanity check"); diff -r 2cb5d5f6d5e5 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/classLoaderData.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "gc_implementation/g1/concurrentMark.inline.hpp" #include "gc_implementation/g1/concurrentMarkThread.inline.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -464,7 +464,7 @@ bool G1CollectedHeap::is_scavengable(con HeapRegion* hr = heap_region_containing(p); if (hr == NULL) { // null - assert(p == NULL, err_msg("Not NULL " PTR_FORMAT ,p)); + assert(p == NULL || MetaspaceShared::is_shared_object(p), err_msg("Not NULL " PTR_FORMAT ,p)); return false; } else { return !hr->isHumongous(); @@ -3061,8 +3061,8 @@ public: template void do_oop_work(T *p) { oop obj = oopDesc::load_decode_heap_oop(p); - guarantee(obj == NULL || !_g1h->is_obj_dead_cond(obj, _vo), - "Dead object referenced by a not dead object"); + guarantee(obj == NULL || !_g1h->is_obj_dead_cond(obj, _vo) || obj->is_shared(), + err_msg("Dead object referenced by a not dead object: " PTR_FORMAT, obj)); } }; diff -r 2cb5d5f6d5e5 src/share/vm/gc_implementation/g1/g1MarkSweep.cpp --- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp --- a/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -165,7 +165,7 @@ inline void G1UpdateRSOrPushRefOopClosur oopDesc* o = obj; #endif // CHECK_UNHANDLED_OOPS assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned"); - assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); + assert(Universe::is_in_reserved_heap_or_shared(obj), err_msg("must be in heap or shared: " PTR_FORMAT, obj)); } #endif // ASSERT diff -r 2cb5d5f6d5e5 src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp --- a/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -57,7 +57,7 @@ inline void G1RemSet::par_write_ref(Heap oopDesc* o = obj; #endif // CHECK_UNHANDLED_OOPS assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned"); - assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); + assert(Universe::is_in_reserved_heap_or_shared(obj), err_msg("must be in heap or shared: " PTR_FORMAT, obj)); } #endif // ASSERT diff -r 2cb5d5f6d5e5 src/share/vm/gc_implementation/g1/heapRegion.cpp --- a/src/share/vm/gc_implementation/g1/heapRegion.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -99,6 +99,10 @@ public: T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + // Don't verify shared objects. + if (obj->is_shared()) { + return; + } bool failed = false; if (!_g1h->is_in_closed_subset(obj) || _g1h->is_obj_dead_cond(obj, _vo)) { MutexLockerEx x(ParGCRareEvent_lock, diff -r 2cb5d5f6d5e5 src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp --- a/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -47,9 +47,7 @@ inline HeapRegion* HeapRegionSeq::addr_t } inline HeapRegion* HeapRegionSeq::addr_to_region(HeapWord* addr) const { - if (addr != NULL && addr < _heap_end) { - assert(addr >= _heap_bottom, - err_msg("addr: "PTR_FORMAT" bottom: "PTR_FORMAT, addr, _heap_bottom)); + if (addr != NULL && _heap_bottom <= addr && addr < _heap_end) { return addr_to_region_unsafe(addr); } return NULL; diff -r 2cb5d5f6d5e5 src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "code/codeCache.hpp" #include "gc_implementation/parallelScavenge/cardTableExtension.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/gc_implementation/shared/markSweep.inline.hpp --- a/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -51,21 +51,28 @@ template inline void MarkSweep if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); if (!obj->mark()->is_marked()) { - mark_object(obj); - obj->follow_contents(); + // Don't mark or follow shared objects. + if (!obj->is_shared()) { + mark_object(obj); + obj->follow_contents(); + } } } follow_stack(); } template inline void MarkSweep::mark_and_push(T* p) { -// assert(Universe::heap()->is_in_reserved(p), "should be in object space"); + // We are also marking oops stored outside the reserved heap, e.g. ClassLoaderData, + // that's why we can't assert here on Universe::heap()->is_in_reserved(p). T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); if (!obj->mark()->is_marked()) { - mark_object(obj); - _marking_stack.push(obj); + // Don't mark or push shared objects. + if (!obj->is_shared()) { + mark_object(obj); + _marking_stack.push(obj); + } } } } @@ -79,17 +86,20 @@ void MarkSweep::push_objarray(oop obj, s template inline void MarkSweep::adjust_pointer(T* p) { T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { - oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - oop new_obj = oop(obj->mark()->decode_pointer()); - assert(new_obj != NULL || // is forwarding ptr? - obj->mark() == markOopDesc::prototype() || // not gc marked? - (UseBiasedLocking && obj->mark()->has_bias_pattern()), - // not gc marked? - "should be forwarded"); - if (new_obj != NULL) { - assert(Universe::heap()->is_in_reserved(new_obj), - "should be in object space"); - oopDesc::encode_store_heap_oop_not_null(p, new_obj); + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + // Don't adjust shared objects. + if (!obj->is_shared()) { + oop new_obj = oop(obj->mark()->decode_pointer()); + assert(new_obj != NULL || // is forwarding ptr? + obj->mark() == markOopDesc::prototype() || // not gc marked? + (UseBiasedLocking && obj->mark()->has_bias_pattern()), + // not gc marked? + "should be forwarded"); + if (new_obj != NULL) { + assert(Universe::heap()->is_in_reserved(new_obj), + err_msg("should be in object space: obj=" PTR_FORMAT ", new_obj=" PTR_FORMAT, obj, new_obj)); + oopDesc::encode_store_heap_oop_not_null(p, new_obj); + } } } } diff -r 2cb5d5f6d5e5 src/share/vm/gc_interface/collectedHeap.hpp --- a/src/share/vm/gc_interface/collectedHeap.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/gc_interface/collectedHeap.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -77,6 +77,8 @@ class GCHeapLog : public EventLogBase { friend class VMStructs; friend class IsGCActiveMark; // Block structured external access to _is_gc_active + friend class InstanceKlass; + friend class TypeArrayKlass; #ifdef ASSERT static int _fire_out_of_memory_count; diff -r 2cb5d5f6d5e5 src/share/vm/interpreter/interpreterRuntime.cpp --- a/src/share/vm/interpreter/interpreterRuntime.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -652,7 +652,7 @@ IRT_ENTRY(void, InterpreterRuntime::reso Symbol* signature = call.signature(); receiver = Handle(thread, thread->last_frame().interpreter_callee_receiver(signature)); - assert(Universe::heap()->is_in_reserved_or_null(receiver()), + assert(Universe::is_in_reserved_heap_or_shared_or_null(receiver()), "sanity check"); assert(receiver.is_null() || !Universe::heap()->is_in_reserved(receiver->klass()), diff -r 2cb5d5f6d5e5 src/share/vm/memory/defNewGeneration.cpp --- a/src/share/vm/memory/defNewGeneration.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/memory/defNewGeneration.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -760,7 +760,7 @@ void DefNewGeneration::handle_promotion_ oop DefNewGeneration::copy_to_survivor_space(oop old) { assert(is_in_reserved(old) && !old->is_forwarded(), - "shouldn't be scavenging this oop"); + err_msg("shouldn't be scavenging this oop: " PTR_FORMAT, old)); size_t s = old->size(); oop obj = NULL; diff -r 2cb5d5f6d5e5 src/share/vm/memory/genCollectedHeap.cpp --- a/src/share/vm/memory/genCollectedHeap.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/memory/genCollectedHeap.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -809,7 +809,7 @@ void GenCollectedHeap::do_full_collectio bool GenCollectedHeap::is_in_young(oop p) { bool result = ((HeapWord*)p) < _gens[_n_gens - 1]->reserved().start(); - assert(result == _gens[0]->is_in_reserved(p), + assert(result == _gens[0]->is_in_reserved(p) || p->is_shared(), err_msg("incorrect test - result=%d, p=" PTR_FORMAT, result, (void*)p)); return result; } @@ -840,8 +840,8 @@ bool GenCollectedHeap::is_in(const void* // Don't implement this by using is_in_young(). This method is used // in some cases to check that is_in_young() is correct. bool GenCollectedHeap::is_in_partial_collection(const void* p) { - assert(is_in_reserved(p) || p == NULL, - "Does not work if address is non-null and outside of the heap"); + assert(is_in_reserved_or_null(p) && !MetaspaceShared::is_shared_object(p), + err_msg("does not work if address is non-null and outside of the heap: " PTR_FORMAT, p)); return p < _gens[_n_gens - 2]->reserved().end() && p != NULL; } #endif diff -r 2cb5d5f6d5e5 src/share/vm/memory/genMarkSweep.cpp --- a/src/share/vm/memory/genMarkSweep.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/memory/genMarkSweep.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/memory/metaspaceShared.cpp --- a/src/share/vm/memory/metaspaceShared.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/memory/metaspaceShared.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -26,6 +26,7 @@ #include "classfile/dictionary.hpp" #include "classfile/loaderConstraints.hpp" #include "classfile/placeholders.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" @@ -276,6 +277,20 @@ public: void doit(); // outline because gdb sucks }; // class VM_PopulateDumpSharedSpace +/** + * Walk over all classes in the system and intern the strings in the + * constant pools into the shared string table. + */ +static void populate_shared_string_table() { + Thread* THREAD = Thread::current(); + for (int i = 0; i < _global_klass_objects->length(); i++) { + Klass* k = _global_klass_objects->at(i); + if (k->oop_is_instance()) { + InstanceKlass* ik = (InstanceKlass*) k; + ik->constants()->resolve_string_constants(CATCH); + } + } +} void VM_PopulateDumpSharedSpace::doit() { Thread* THREAD = VMThread::vm_thread(); @@ -305,12 +320,19 @@ void VM_PopulateDumpSharedSpace::doit() // Update all the fingerprints in the shared methods. tty->print("Calculating fingerprints ... "); calculate_fingerprints(); - tty->print_cr("done. "); + tty->print_cr("done."); + + // Populate the shared string table + if (UseG1GC) { + tty->print("Populating shared string table ... "); + populate_shared_string_table(); + tty->print_cr("done."); + } // Remove all references outside the metadata tty->print("Removing unshareable information ... "); remove_unshareable_in_classes(); - tty->print_cr("done. "); + tty->print_cr("done."); // Set up the share data and shared code segments. char* md_low = _md_vs.low(); @@ -345,8 +367,8 @@ void VM_PopulateDumpSharedSpace::doit() NOT_PRODUCT(SystemDictionary::verify();) - // Copy the the symbol table, and the system dictionary to the shared - // space in usable form. Copy the hastable + // Copy the symbol table, the string table, and the system dictionary to the shared + // space in usable form. Copy the hashtable // buckets first [read-write], then copy the linked lists of entries // [read-only]. @@ -354,6 +376,12 @@ void VM_PopulateDumpSharedSpace::doit() NOT_PRODUCT(SymbolTable::verify()); SymbolTable::copy_buckets(&md_top, md_end); + if (UseG1GC) { + StringTable::reverse(md_top); + NOT_PRODUCT(StringTable::verify()); + StringTable::copy_buckets(&md_top, md_end); + } + SystemDictionary::reverse(); SystemDictionary::copy_buckets(&md_top, md_end); @@ -362,7 +390,13 @@ void VM_PopulateDumpSharedSpace::doit() ClassLoader::verify(); SymbolTable::copy_table(&md_top, md_end); + + if (UseG1GC) { + StringTable::copy_table(&md_top, md_end); + } + SystemDictionary::copy_table(&md_top, md_end); + ClassLoader::verify(); ClassLoader::copy_package_info_table(&md_top, md_end); ClassLoader::verify(); @@ -627,6 +661,10 @@ void MetaspaceShared::preload_and_dump(T exit(1); } + if (PrintStringTableStatistics) { + StringTable::dump(tty); + } + // Since various initialization steps have been undone by this process, // it is not reasonable to continue running a java process. exit(0); @@ -780,46 +818,63 @@ void MetaspaceShared::initialize_shared_ // Create the symbol table using the bucket array at this spot in the // misc data space. Since the symbol table is often modified, this // region (of mapped pages) will be copy-on-write. + { + int length = *(intptr_t*)buffer; + buffer += sizeof(intptr_t); + int number_of_entries = *(intptr_t*)buffer; + buffer += sizeof(intptr_t); + SymbolTable::create_table((HashtableBucket*)buffer, length, number_of_entries); + buffer += length; + NOT_PRODUCT(SymbolTable::verify()); + } - int symbolTableLen = *(intptr_t*)buffer; - buffer += sizeof(intptr_t); - int number_of_entries = *(intptr_t*)buffer; - buffer += sizeof(intptr_t); - SymbolTable::create_table((HashtableBucket*)buffer, symbolTableLen, - number_of_entries); - buffer += symbolTableLen; + // Create the shared string table using the bucket array at this spot in the + // misc data space. Since the shared string table is almost never + // modified, this region (of mapped pages) will be (effectively, if + // not explicitly) read-only. + { + int length = *(intptr_t*)buffer; + buffer += sizeof(intptr_t); + int number_of_entries = *(intptr_t*)buffer; + buffer += sizeof(intptr_t); + if (UseG1GC) { + StringTable::create_shared_table((HashtableBucket*)buffer, length, number_of_entries); + } + buffer += length; + // Note: We cannot verify the shared string table here because + // java/lang/String is not initialized yet. + } // Create the shared dictionary using the bucket array at this spot in // the misc data space. Since the shared dictionary table is never // modified, this region (of mapped pages) will be (effectively, if // not explicitly) read-only. - - int sharedDictionaryLen = *(intptr_t*)buffer; - buffer += sizeof(intptr_t); - number_of_entries = *(intptr_t*)buffer; - buffer += sizeof(intptr_t); - SystemDictionary::set_shared_dictionary((HashtableBucket*)buffer, - sharedDictionaryLen, - number_of_entries); - buffer += sharedDictionaryLen; + { + int length = *(intptr_t*)buffer; + buffer += sizeof(intptr_t); + int number_of_entries = *(intptr_t*)buffer; + buffer += sizeof(intptr_t); + SystemDictionary::set_shared_dictionary((HashtableBucket*)buffer, length, number_of_entries); + buffer += length; + } // Create the package info table using the bucket array at this spot in // the misc data space. Since the package info table is never // modified, this region (of mapped pages) will be (effectively, if // not explicitly) read-only. - - int pkgInfoLen = *(intptr_t*)buffer; - buffer += sizeof(intptr_t); - number_of_entries = *(intptr_t*)buffer; - buffer += sizeof(intptr_t); - ClassLoader::create_package_info_table((HashtableBucket*)buffer, pkgInfoLen, - number_of_entries); - buffer += pkgInfoLen; - ClassLoader::verify(); + { + int length = *(intptr_t*)buffer; + buffer += sizeof(intptr_t); + int number_of_entries = *(intptr_t*)buffer; + buffer += sizeof(intptr_t); + ClassLoader::create_package_info_table((HashtableBucket*)buffer, length, number_of_entries); + buffer += length; + ClassLoader::verify(); + } // The following data in the shared misc data region are the linked - // list elements (HashtableEntry objects) for the symbol table, string - // table, and shared dictionary. The heap objects refered to by the + // list elements (HashtableEntry objects) for the symbol table, shared string + // table, and shared dictionary. The heap objects referred to by the // symbol table, string table, and shared dictionary are permanent and // unmovable. Since new entries added to the string and symbol tables // are always added at the beginning of the linked lists, THESE LINKED @@ -829,6 +884,10 @@ void MetaspaceShared::initialize_shared_ buffer += sizeof(intptr_t); buffer += len; + len = *(intptr_t*)buffer; // skip over shared string table entries + buffer += sizeof(intptr_t); + buffer += len; + len = *(intptr_t*)buffer; // skip over shared dictionary entries buffer += sizeof(intptr_t); buffer += len; diff -r 2cb5d5f6d5e5 src/share/vm/memory/metaspaceShared.hpp --- a/src/share/vm/memory/metaspaceShared.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/memory/metaspaceShared.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -84,6 +84,20 @@ class MetaspaceShared : AllStatic { // Return true if given address is in the mapped shared space. static bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false); + /** + * Return true if give address is a shared object in shared space. + */ + static bool is_shared_object(const void* p) { +#if INCLUDE_CDS + if (UseSharedSpaces) { + return is_in_shared_space(p); + } else if (DumpSharedSpaces) { + return Metaspace::contains(p); + } +#endif + return false; + } + static void generate_vtable_methods(void** vtbl_list, void** vtable, char** md_top, char* md_end, diff -r 2cb5d5f6d5e5 src/share/vm/memory/oopFactory.hpp --- a/src/share/vm/memory/oopFactory.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/memory/oopFactory.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -65,6 +65,11 @@ class oopFactory: AllStatic { // Regular object arrays static objArrayOop new_objArray(Klass* klass, int length, TRAPS); + + static typeArrayOop new_metaspace_charArray(ClassLoaderData* loader_data, int length, TRAPS) { + TypeArrayKlass* k = TypeArrayKlass::cast(Universe::charArrayKlassObj()); + return k->allocate_metaspace(loader_data, length, false, CHECK_NULL); + } }; #endif // SHARE_VM_MEMORY_OOPFACTORY_HPP diff -r 2cb5d5f6d5e5 src/share/vm/memory/sharedHeap.cpp --- a/src/share/vm/memory/sharedHeap.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/memory/sharedHeap.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/memory/universe.cpp --- a/src/share/vm/memory/universe.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/memory/universe.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -26,6 +26,7 @@ #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" @@ -104,8 +105,6 @@ oop Universe::_main_thread_group oop Universe::_system_thread_group = NULL; objArrayOop Universe::_the_empty_class_klass_array = NULL; Array* Universe::_the_array_interfaces_array = NULL; -oop Universe::_the_null_string = NULL; -oop Universe::_the_min_jint_string = NULL; LatestMethodOopCache* Universe::_finalizer_register_cache = NULL; LatestMethodOopCache* Universe::_loader_addClass_cache = NULL; ActiveMethodOopsCache* Universe::_reflect_invoke_cache = NULL; @@ -176,13 +175,11 @@ void Universe::oops_do(OopClosure* f, bo assert(_mirrors[0] == NULL && _mirrors[T_BOOLEAN - 1] == NULL, "checking"); f->do_oop((oop*)&_the_empty_class_klass_array); - f->do_oop((oop*)&_the_null_string); - f->do_oop((oop*)&_the_min_jint_string); f->do_oop((oop*)&_out_of_memory_error_java_heap); f->do_oop((oop*)&_out_of_memory_error_perm_gen); f->do_oop((oop*)&_out_of_memory_error_array_size); f->do_oop((oop*)&_out_of_memory_error_gc_overhead_limit); - f->do_oop((oop*)&_preallocated_out_of_memory_error_array); + f->do_oop((oop*)&_preallocated_out_of_memory_error_array); f->do_oop((oop*)&_null_ptr_exception_instance); f->do_oop((oop*)&_arithmetic_exception_instance); f->do_oop((oop*)&_virtual_machine_error_instance); @@ -289,9 +286,6 @@ void Universe::genesis(TRAPS) { Klass* ok = SystemDictionary::Object_klass(); - _the_null_string = StringTable::intern("null", CHECK); - _the_min_jint_string = StringTable::intern("-2147483648", CHECK); - if (UseSharedSpaces) { // Verify shared interfaces array. assert(_the_array_interfaces_array->at(0) == @@ -656,6 +650,9 @@ jint universe_init() { MetaspaceShared::initialize_shared_spaces(); StringTable::create_table(); } else { + if (DumpSharedSpaces && UseG1GC) { + StringTable::create_shared_table(); + } SymbolTable::create_table(); StringTable::create_table(); ClassLoader::create_package_info_table(); @@ -1318,6 +1315,44 @@ void Universe::verify(VerifyOption optio _verify_in_progress = false; } +/** + * Checks if the address is in either the heap or a shared object. + */ +bool Universe::is_in_heap_or_shared(const void* p) { + return MetaspaceShared::is_shared_object(p) || heap()->is_in(p); +} + +/** + * Checks if the address is in either the heap or a shared object + * or null. + */ +bool Universe::is_in_heap_or_shared_or_null(const void* p) { + return p == NULL || is_in_heap_or_shared(p); +} + +/** + * Checks if the address is in either the reserved heap or a shared object. + */ +bool Universe::is_in_reserved_heap_or_shared(const void* p) { + return MetaspaceShared::is_shared_object(p) || heap()->is_in_reserved(p); +} + +/** + * Checks if the address is in either the reserved heap or a shared object + * or null. + */ +bool Universe::is_in_reserved_heap_or_shared_or_null(const void* p) { + return p == NULL || is_in_reserved_heap_or_shared(p); +} + +/** + * Checks if the address is in either a heap closed subset or the + * meta space. + */ +bool Universe::is_in_heap_closed_subset_or_shared(const void* p) { + return MetaspaceShared::is_shared_object(p) || heap()->is_in_closed_subset(p); +} + // Oop verification (see MacroAssembler::verify_oop) static uintptr_t _verify_oop_data[2] = {0, (uintptr_t)-1}; diff -r 2cb5d5f6d5e5 src/share/vm/memory/universe.hpp --- a/src/share/vm/memory/universe.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/memory/universe.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -172,8 +172,6 @@ class Universe: AllStatic { static oop _system_thread_group; // Reference to the system thread group object static objArrayOop _the_empty_class_klass_array; // Canonicalized obj array of type java.lang.Class - static oop _the_null_string; // A cache of "null" as a Java string - static oop _the_min_jint_string; // A cache of "-2147483648" as a Java string static LatestMethodOopCache* _finalizer_register_cache; // static method for registering finalizable objects static LatestMethodOopCache* _loader_addClass_cache; // method for registering loaded classes in class loader vector static ActiveMethodOopsCache* _reflect_invoke_cache; // method for security checks @@ -342,8 +340,6 @@ class Universe: AllStatic { static objArrayOop the_empty_class_klass_array () { return _the_empty_class_klass_array; } static Array* the_array_interfaces_array() { return _the_array_interfaces_array; } - static oop the_null_string() { return _the_null_string; } - static oop the_min_jint_string() { return _the_min_jint_string; } static Method* finalizer_register_method() { return _finalizer_register_cache->get_Method(); } static Method* loader_addClass_method() { return _loader_addClass_cache->get_Method(); } static ActiveMethodOopsCache* reflect_invoke_cache() { return _reflect_invoke_cache; } @@ -453,6 +449,12 @@ class Universe: AllStatic { verify("", silent); } + static bool is_in_heap_or_shared(const void* p); + static bool is_in_heap_or_shared_or_null(const void* p); + static bool is_in_reserved_heap_or_shared(const void* p); + static bool is_in_reserved_heap_or_shared_or_null(const void* p); + static bool is_in_heap_closed_subset_or_shared(const void* p); + static int verify_count() { return _verify_count; } // The default behavior is to call print_on() on gclog_or_tty. static void print(); diff -r 2cb5d5f6d5e5 src/share/vm/oops/constantPool.cpp --- a/src/share/vm/oops/constantPool.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/oops/constantPool.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -26,6 +26,7 @@ #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.hpp" #include "classfile/metadataOnStackMark.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" @@ -865,9 +866,11 @@ oop ConstantPool::resolve_bootstrap_spec oop ConstantPool::string_at_impl(constantPoolHandle this_oop, int which, int obj_index, TRAPS) { // 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; + 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"); diff -r 2cb5d5f6d5e5 src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/oops/instanceKlass.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -36,6 +36,7 @@ #include "memory/genOopClosures.inline.hpp" #include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" +#include "memory/metaspace.hpp" #include "memory/oopFactory.hpp" #include "oops/fieldStreams.hpp" #include "oops/instanceClassLoaderKlass.hpp" @@ -1026,18 +1027,30 @@ instanceOop InstanceKlass::register_fina } instanceOop InstanceKlass::allocate_instance(TRAPS) { - bool has_finalizer_flag = has_finalizer(); // Query before possible GC - int size = size_helper(); // Query before forming handle. - + const bool has_finalizer_flag = has_finalizer(); // Query before possible GC + const int size = size_helper(); // Query before forming handle. KlassHandle h_k(THREAD, this); - - instanceOop i; - - i = (instanceOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL); + instanceOop obj = (instanceOop) CollectedHeap::obj_allocate(h_k, size, CHECK_NULL); if (has_finalizer_flag && !RegisterFinalizersAtInit) { - i = register_finalizer(i, CHECK_NULL); + obj = register_finalizer(obj, CHECK_NULL); } - return i; + return obj; +} + +instanceOop InstanceKlass::allocate_metaspace_instance(ClassLoaderData* loader_data, TRAPS) { + const bool has_finalizer_flag = has_finalizer(); // Query before possible GC + const int size = size_helper(); + const bool read_only = true; + instanceOop obj = (instanceOop) Metaspace::allocate(loader_data, size, read_only, Metaspace::NonClassType, CHECK_NULL); + + // Do the same initialization as in CollectedHeap::obj_allocate + CollectedHeap::init_obj((HeapWord*)obj, size); + CollectedHeap::post_allocation_setup_obj(this, (HeapWord*)obj); + + if (has_finalizer_flag && !RegisterFinalizersAtInit) { + obj = register_finalizer(obj, CHECK_NULL); + } + return obj; } void InstanceKlass::check_valid_for_instantiation(bool throwError, TRAPS) { @@ -1897,22 +1910,22 @@ template void assert_is_in(T * T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in(o), "should be in heap"); + assert(Universe::is_in_heap_or_shared(o), err_msg("should be in heap or metaspace: " PTR_FORMAT, o)); } } template void assert_is_in_closed_subset(T *p) { T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in_closed_subset(o), - err_msg("should be in closed *p " INTPTR_FORMAT " " INTPTR_FORMAT, (address)p, (address)o)); + assert(Universe::is_in_heap_closed_subset_or_shared(o), + err_msg("should be in closed subset: p=" INTPTR_FORMAT ", o=" INTPTR_FORMAT, (address)p, (address)o)); } } template void assert_is_in_reserved(T *p) { T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in_reserved(o), "should be in reserved"); + assert(Universe::heap()->is_in_reserved(o), err_msg("should be in reserved: " PTR_FORMAT, o)); } } template void assert_nothing(T *p) {} diff -r 2cb5d5f6d5e5 src/share/vm/oops/instanceKlass.hpp --- a/src/share/vm/oops/instanceKlass.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/oops/instanceKlass.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -689,6 +689,7 @@ class InstanceKlass: public Klass { } // allocation instanceOop allocate_instance(TRAPS); + instanceOop allocate_metaspace_instance(ClassLoaderData* loader_data, TRAPS); // additional member function to return a handle instanceHandle allocate_instance_handle(TRAPS) { return instanceHandle(THREAD, allocate_instance(THREAD)); } diff -r 2cb5d5f6d5e5 src/share/vm/oops/instanceMirrorKlass.cpp --- a/src/share/vm/oops/instanceMirrorKlass.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/oops/instanceMirrorKlass.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -55,21 +55,21 @@ template void assert_is_in(T * T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in(o), "should be in heap"); + assert(Universe::is_in_heap_or_shared(o), err_msg("should be in heap or shared: " PTR_FORMAT, o)); } } template void assert_is_in_closed_subset(T *p) { T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in_closed_subset(o), "should be in closed"); + assert(Universe::is_in_heap_closed_subset_or_shared(o), err_msg("should be in closed subset or shared: " PTR_FORMAT, o)); } } template void assert_is_in_reserved(T *p) { T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in_reserved(o), "should be in reserved"); + assert(Universe::heap()->is_in_reserved(o), err_msg("should be in reserved: " PTR_FORMAT, o)); } } template void assert_nothing(T *p) {} diff -r 2cb5d5f6d5e5 src/share/vm/oops/instanceRefKlass.cpp --- a/src/share/vm/oops/instanceRefKlass.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/oops/instanceRefKlass.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -56,6 +56,10 @@ void specialized_oop_follow_contents(Ins ) if (!oopDesc::is_null(heap_oop)) { oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); + // Don't follow shared objects. + if (referent->is_shared()) { + return; + } if (!referent->is_gc_marked() && MarkSweep::ref_processor()->discover_reference(obj, ref->reference_type())) { // reference was discovered, referent will be traversed later @@ -135,6 +139,10 @@ void specialized_oop_follow_contents(Ins ) if (!oopDesc::is_null(heap_oop)) { oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); + // Don't follow shared objects. + if (referent->is_shared()) { + return; + } if (PSParallelCompact::mark_bitmap()->is_unmarked(referent) && PSParallelCompact::ref_processor()-> discover_reference(obj, ref->reference_type())) { diff -r 2cb5d5f6d5e5 src/share/vm/oops/oop.hpp --- a/src/share/vm/oops/oop.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/oops/oop.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -313,6 +313,7 @@ class oopDesc { // Forward pointer operations for scavenge bool is_forwarded() const; + bool is_shared() const; void forward_to(oop p); bool cas_forward_to(oop p, markOop compare); diff -r 2cb5d5f6d5e5 src/share/vm/oops/oop.inline.hpp --- a/src/share/vm/oops/oop.inline.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/oops/oop.inline.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -32,6 +32,7 @@ #include "memory/cardTableModRefBS.hpp" #include "memory/genCollectedHeap.hpp" #include "memory/generation.hpp" +#include "memory/metaspaceShared.hpp" #include "memory/specialized_oop_closures.hpp" #include "oops/arrayKlass.hpp" #include "oops/arrayOop.hpp" @@ -607,10 +608,16 @@ inline bool oopDesc::has_bias_pattern() // used only for asserts inline bool oopDesc::is_oop(bool ignore_mark_word) const { oop obj = (oop) this; - if (!check_obj_alignment(obj)) return false; - if (!Universe::heap()->is_in_reserved(obj)) return false; + if (!check_obj_alignment(obj)) { + return false; + } + if (!Universe::is_in_reserved_heap_or_shared(obj)) { + return false; + } // obj is aligned and accessible in heap - if (Universe::heap()->is_in_reserved(obj->klass_or_null())) return false; + if (Universe::heap()->is_in_reserved(obj->klass_or_null())) { + return false; + } // Header verification: the mark is typically non-NULL. If we're // at a safepoint, it must not be null. @@ -652,6 +659,13 @@ inline bool oopDesc::is_forwarded() cons return mark()->is_marked(); } +/** + * Return true if this object is a shared object. + */ +inline bool oopDesc::is_shared() const { + return MetaspaceShared::is_shared_object(this); +} + // Used by scavengers inline void oopDesc::forward_to(oop p) { assert(check_obj_alignment(p), diff -r 2cb5d5f6d5e5 src/share/vm/oops/typeArrayKlass.cpp --- a/src/share/vm/oops/typeArrayKlass.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/oops/typeArrayKlass.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -101,7 +101,6 @@ typeArrayOop TypeArrayKlass::allocate_co size_t size = typeArrayOopDesc::object_size(layout_helper(), length); KlassHandle h_k(THREAD, this); typeArrayOop t; - CollectedHeap* ch = Universe::heap(); if (do_zero) { t = (typeArrayOop)CollectedHeap::array_allocate(h_k, (int)size, length, CHECK_NULL); } else { @@ -118,6 +117,32 @@ typeArrayOop TypeArrayKlass::allocate_co } } +typeArrayOop TypeArrayKlass::allocate_metaspace(ClassLoaderData* loader_data, int length, bool do_zero, TRAPS) { + assert(log2_element_size() >= 0, "bad scale"); + if (length >= 0) { + if (length <= max_length()) { + size_t size = typeArrayOopDesc::object_size(layout_helper(), length); + const bool read_only = true; + typeArrayOop t = (typeArrayOop) Metaspace::allocate(loader_data, size, read_only, Metaspace::NonClassType, CHECK_NULL); + + // Do the same initialization as in CollectedHeap::array_allocate + CollectedHeap::init_obj((HeapWord*)t, size); + CollectedHeap::post_allocation_setup_array(this, (HeapWord*)t, length); + + if (do_zero) { + warning("TODO: zero metaspace array"); + } + return t; + } else { + report_java_out_of_memory("Requested array size exceeds VM limit"); + JvmtiExport::post_array_size_exhausted(); + THROW_OOP_0(Universe::out_of_memory_error_array_size()); + } + } else { + THROW_0(vmSymbols::java_lang_NegativeArraySizeException()); + } +} + oop TypeArrayKlass::multi_allocate(int rank, jint* last_size, TRAPS) { // For typeArrays this is only called for the last dimension assert(rank == 1, "just checking"); diff -r 2cb5d5f6d5e5 src/share/vm/oops/typeArrayKlass.hpp --- a/src/share/vm/oops/typeArrayKlass.hpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/oops/typeArrayKlass.hpp Sun Sep 29 11:48:00 2013 -0700 @@ -65,6 +65,7 @@ class TypeArrayKlass : public ArrayKlass // Allocation typeArrayOop allocate_common(int length, bool do_zero, TRAPS); typeArrayOop allocate(int length, TRAPS) { return allocate_common(length, true, THREAD); } + typeArrayOop allocate_metaspace(ClassLoaderData* loader_data, int length, bool do_zero, TRAPS); oop multi_allocate(int rank, jint* sizes, TRAPS); oop protection_domain() const { return NULL; } diff -r 2cb5d5f6d5e5 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/prims/jvm.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -26,6 +26,7 @@ #include "classfile/classLoader.hpp" #include "classfile/javaAssertions.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/prims/methodHandles.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "compiler/compileBroker.hpp" #include "interpreter/interpreter.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/prims/whitebox.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -27,6 +27,7 @@ #include "memory/universe.hpp" #include "oops/oop.inline.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/classLoaderData.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/runtime/arguments.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/javaAssertions.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "compiler/compilerOracle.hpp" #include "memory/allocation.inline.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/runtime/frame.cpp --- a/src/share/vm/runtime/frame.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/runtime/frame.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -1082,7 +1082,7 @@ oop frame::retrieve_receiver(RegisterMap return NULL; } oop r = *oop_adr; - assert(Universe::heap()->is_in_or_null(r), err_msg("bad receiver: " INTPTR_FORMAT " (" INTX_FORMAT ")", (intptr_t) r, (intptr_t) r)); + assert(Universe::is_in_heap_or_shared_or_null(r), err_msg("bad receiver: " INTPTR_FORMAT " (" INTX_FORMAT ")", (intptr_t) r, (intptr_t) r)); return r; } diff -r 2cb5d5f6d5e5 src/share/vm/runtime/init.cpp --- a/src/share/vm/runtime/init.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/runtime/init.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "code/icBuffer.hpp" #include "gc_interface/collectedHeap.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/runtime/jniHandles.cpp --- a/src/share/vm/runtime/jniHandles.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/runtime/jniHandles.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -35,13 +35,19 @@ JNIHandleBlock* JNIHandles::_global_hand JNIHandleBlock* JNIHandles::_weak_global_handles = NULL; oop JNIHandles::_deleted_handle = NULL; +/** + * Helper function to assert if an address is in the heap or a shared object. + */ +static void assert_in_reserved_heap_or_shared(const void* p) { + assert(Universe::is_in_reserved_heap_or_shared(p), err_msg("not in reserved heap or shared: " PTR_FORMAT, p)); +} jobject JNIHandles::make_local(oop obj) { if (obj == NULL) { return NULL; // ignore null handles } else { Thread* thread = Thread::current(); - assert(Universe::heap()->is_in_reserved(obj), "sanity check"); + assert_in_reserved_heap_or_shared(obj); return thread->active_handles()->allocate_handle(obj); } } @@ -53,7 +59,7 @@ jobject JNIHandles::make_local(Thread* t if (obj == NULL) { return NULL; // ignore null handles } else { - assert(Universe::heap()->is_in_reserved(obj), "sanity check"); + assert_in_reserved_heap_or_shared(obj); return thread->active_handles()->allocate_handle(obj); } } @@ -64,7 +70,7 @@ jobject JNIHandles::make_local(JNIEnv* e return NULL; // ignore null handles } else { JavaThread* thread = JavaThread::thread_from_jni_environment(env); - assert(Universe::heap()->is_in_reserved(obj), "sanity check"); + assert_in_reserved_heap_or_shared(obj); return thread->active_handles()->allocate_handle(obj); } } @@ -76,7 +82,7 @@ jobject JNIHandles::make_global(Handle o if (!obj.is_null()) { // ignore null handles MutexLocker ml(JNIGlobalHandle_lock); - assert(Universe::heap()->is_in_reserved(obj()), "sanity check"); + assert_in_reserved_heap_or_shared(obj()); res = _global_handles->allocate_handle(obj()); } else { CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); @@ -92,7 +98,7 @@ jobject JNIHandles::make_weak_global(Han if (!obj.is_null()) { // ignore null handles MutexLocker ml(JNIGlobalHandle_lock); - assert(Universe::heap()->is_in_reserved(obj()), "sanity check"); + assert_in_reserved_heap_or_shared(obj()); res = _weak_global_handles->allocate_handle(obj()); } else { CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); @@ -413,7 +419,7 @@ void JNIHandleBlock::weak_oops_do(BoolOb jobject JNIHandleBlock::allocate_handle(oop obj) { - assert(Universe::heap()->is_in_reserved(obj), "sanity check"); + assert_in_reserved_heap_or_shared(obj); if (_top == 0) { // This is the first allocation or the initial block got zapped when // entering a native function. If we have any following blocks they are diff -r 2cb5d5f6d5e5 src/share/vm/runtime/reflection.cpp --- a/src/share/vm/runtime/reflection.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/runtime/reflection.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/verifier.hpp" diff -r 2cb5d5f6d5e5 src/share/vm/runtime/safepoint.cpp --- a/src/share/vm/runtime/safepoint.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/runtime/safepoint.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" @@ -1054,7 +1055,7 @@ void ThreadSafepointState::handle_pollin oop result = caller_fr.saved_oop_result(&map); assert(result == NULL || result->is_oop(), "must be oop"); return_value = Handle(thread(), result); - assert(Universe::heap()->is_in_or_null(result), "must be heap pointer"); + assert(Universe::is_in_heap_or_shared_or_null(result), err_msg("must be in heap or shared: " PTR_FORMAT, result)); } // Block the thread diff -r 2cb5d5f6d5e5 src/share/vm/runtime/synchronizer.cpp --- a/src/share/vm/runtime/synchronizer.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/runtime/synchronizer.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -621,13 +621,18 @@ intptr_t ObjectSynchronizer::FastHashCod } // hashCode() is a heap mutator ... - // Relaxing assertion for bug 6320749. - assert (Universe::verify_in_progress() || - !SafepointSynchronize::is_at_safepoint(), "invariant") ; - assert (Universe::verify_in_progress() || - Self->is_Java_thread() , "invariant") ; - assert (Universe::verify_in_progress() || - ((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ; +#ifdef ASSERT + // If we are dumping shared spaces it's okay to get the hash for + // shared objects at any time. + if (DumpSharedSpaces) { + assert(obj->is_shared(), err_msg("must be a shared object: " PTR_FORMAT, obj)); + } else { + // Relaxing assertion for bug 6320749. + assert(Universe::verify_in_progress() || !SafepointSynchronize::is_at_safepoint(), "invariant") ; + assert(Universe::verify_in_progress() || Self->is_Java_thread(), "invariant") ; + assert(Universe::verify_in_progress() || ((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ; + } +#endif ObjectMonitor* monitor = NULL; markOop temp, test; diff -r 2cb5d5f6d5e5 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Tue Jun 04 22:16:15 2013 -0700 +++ b/src/share/vm/runtime/vmStructs.cpp Sun Sep 29 11:48:00 2013 -0700 @@ -27,6 +27,7 @@ #include "classfile/javaClasses.hpp" #include "classfile/loaderConstraints.hpp" #include "classfile/placeholders.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "ci/ciField.hpp" @@ -608,7 +609,7 @@ typedef BinaryTreeDictionary