--- old/src/share/vm/classfile/symbolTable.cpp 2013-06-11 12:20:02.968378050 -0700 +++ new/src/share/vm/classfile/symbolTable.cpp 2013-06-11 12:20:02.734519610 -0700 @@ -610,6 +610,8 @@ bool StringTable::_needs_rehashing = false; +volatile int StringTable::_parallel_claimed_idx = 0; + // Pick hashing algorithm unsigned int StringTable::hash_string(const jchar* s, int len) { return use_alternate_hashcode() ? AltHashing::murmur3_32(seed(), s, len) : @@ -771,8 +773,18 @@ } } -void StringTable::oops_do(OopClosure* f) { - for (int i = 0; i < the_table()->table_size(); ++i) { +void StringTable::buckets_do(OopClosure* f, int start_idx, int end_idx) { + const int limit = the_table()->table_size(); + + assert(0 <= start_idx && start_idx <= limit, + err_msg("start_idx (" INT32_FORMAT ") oob?", start_idx)); + assert(0 <= end_idx && end_idx <= limit, + err_msg("end_idx (" INT32_FORMAT ") oob?", end_idx)); + assert(start_idx <= end_idx, + err_msg("Ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, + start_idx, end_idx)); + + for (int i = start_idx; i < end_idx; i += 1) { HashtableEntry** p = the_table()->bucket_addr(i); HashtableEntry* entry = the_table()->bucket(i); while (entry != NULL) { @@ -791,6 +803,27 @@ } } +void StringTable::oops_do(OopClosure* f) { + buckets_do(f, 0, the_table()->table_size()); +} + +void StringTable::possibly_parallel_oops_do(OopClosure* f) { + const int ClaimChunkSize = 32; + const int limit = the_table()->table_size(); + + for (;;) { + // Grab next set of buckets to scan + int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; + if (start_idx >= limit) { + // End of table + break; + } + + int end_idx = MIN2(limit, start_idx + ClaimChunkSize); + buckets_do(f, start_idx, end_idx); + } +} + void StringTable::verify() { for (int i = 0; i < the_table()->table_size(); ++i) { HashtableEntry* p = the_table()->bucket(i); --- old/src/share/vm/classfile/symbolTable.hpp 2013-06-11 12:20:04.164695076 -0700 +++ new/src/share/vm/classfile/symbolTable.hpp 2013-06-11 12:20:03.933246378 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -245,12 +245,19 @@ // Set if one bucket is out of balance due to hash algorithm deficiency static bool _needs_rehashing; + // Claimed high water mark for parallel chunked scanning + static volatile int _parallel_claimed_idx; + 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); + // Apply the give oop closure to the entries to the buckets + // in the range [start_idx, end_idx). + static void buckets_do(OopClosure* f, int start_idx, int end_idx); + StringTable() : Hashtable((int)StringTableSize, sizeof (HashtableEntry)) {} @@ -278,9 +285,12 @@ // Delete pointers to otherwise-unreachable objects. static void unlink(BoolObjectClosure* cl); - // Invoke "f->do_oop" on the locations of all oops in the table. + // Serially invoke "f->do_oop" on the locations of all oops in the table. static void oops_do(OopClosure* f); + // Possibly parallel version of the above + static void possibly_parallel_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. @@ -315,5 +325,8 @@ // Rehash the symbol table if it gets out of balance static void rehash_table(); static bool needs_rehashing() { return _needs_rehashing; } + + // Parallel chunked scanning + static void clear_parallel_claimed_index() { _parallel_claimed_idx = 0; } }; #endif // SHARE_VM_CLASSFILE_SYMBOLTABLE_HPP --- old/src/share/vm/memory/sharedHeap.cpp 2013-06-11 12:20:05.296145811 -0700 +++ new/src/share/vm/memory/sharedHeap.cpp 2013-06-11 12:20:05.063526670 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -46,7 +46,6 @@ SH_PS_Management_oops_do, SH_PS_SystemDictionary_oops_do, SH_PS_jvmti_oops_do, - SH_PS_StringTable_oops_do, SH_PS_CodeCache_oops_do, // Leave this one last. SH_PS_NumElements @@ -135,6 +134,8 @@ { if (_active) { outer->change_strong_roots_parity(); + // Zero the claimed high water mark in the StringTable + StringTable::clear_parallel_claimed_index(); } } @@ -163,12 +164,14 @@ // Global (strong) JNI handles if (!_process_strong_tasks->is_task_claimed(SH_PS_JNIHandles_oops_do)) JNIHandles::oops_do(roots); + // All threads execute this; the individual threads are task groups. - if (ParallelGCThreads > 0) { + if (CollectedHeap::use_parallel_gc_threads()) { Threads::possibly_parallel_oops_do(roots, code_roots); } else { Threads::oops_do(roots, code_roots); } + if (!_process_strong_tasks-> is_task_claimed(SH_PS_ObjectSynchronizer_oops_do)) ObjectSynchronizer::oops_do(roots); if (!_process_strong_tasks->is_task_claimed(SH_PS_FlatProfiler_oops_do)) @@ -186,12 +189,20 @@ } } - if (!_process_strong_tasks->is_task_claimed(SH_PS_StringTable_oops_do)) { - if (so & SO_Strings || (!collecting_perm_gen && !JavaObjectsInPerm)) { + // All threads execute the following. A specific chunk of buckets + // from the StringTable are the individual tasks. + if (so & SO_Strings || (!collecting_perm_gen && !JavaObjectsInPerm)) { + if (CollectedHeap::use_parallel_gc_threads()) { + StringTable::possibly_parallel_oops_do(roots); + } else { StringTable::oops_do(roots); } - if (JavaObjectsInPerm) { - // Verify the string table contents are in the perm gen + } + if (JavaObjectsInPerm) { + // Verify the string table contents are in the perm gen + if (CollectedHeap::use_parallel_gc_threads()) { + NOT_PRODUCT(StringTable::possibly_parallel_oops_do(&assert_is_perm_closure)); + } else { NOT_PRODUCT(StringTable::oops_do(&assert_is_perm_closure)); } }