Tue, 19 Aug 2014 02:05:49 -0700
8044406: JVM crash with JDK8 (build 1.8.0-b132) with G1 GC
Summary: Fill the last card that has been allocated into with a dummy object
Reviewed-by: tschatzl, mgerdin
pliden@6413 | 1 | /* |
pliden@6413 | 2 | * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. |
pliden@6413 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
pliden@6413 | 4 | * |
pliden@6413 | 5 | * This code is free software; you can redistribute it and/or modify it |
pliden@6413 | 6 | * under the terms of the GNU General Public License version 2 only, as |
pliden@6413 | 7 | * published by the Free Software Foundation. |
pliden@6413 | 8 | * |
pliden@6413 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
pliden@6413 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
pliden@6413 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
pliden@6413 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
pliden@6413 | 13 | * accompanied this code). |
pliden@6413 | 14 | * |
pliden@6413 | 15 | * You should have received a copy of the GNU General Public License version |
pliden@6413 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
pliden@6413 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
pliden@6413 | 18 | * |
pliden@6413 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
pliden@6413 | 20 | * or visit www.oracle.com if you need additional information or have any |
pliden@6413 | 21 | * questions. |
pliden@6413 | 22 | * |
pliden@6413 | 23 | */ |
pliden@6413 | 24 | |
pliden@6413 | 25 | #include "precompiled.hpp" |
pliden@6413 | 26 | #include "classfile/javaClasses.hpp" |
pliden@6413 | 27 | #include "gc_implementation/g1/g1StringDedupQueue.hpp" |
pliden@6413 | 28 | #include "memory/gcLocker.hpp" |
pliden@6413 | 29 | #include "runtime/mutexLocker.hpp" |
pliden@6413 | 30 | #include "utilities/stack.inline.hpp" |
pliden@6413 | 31 | |
pliden@6413 | 32 | G1StringDedupQueue* G1StringDedupQueue::_queue = NULL; |
pliden@6413 | 33 | const size_t G1StringDedupQueue::_max_size = 1000000; // Max number of elements per queue |
pliden@6413 | 34 | const size_t G1StringDedupQueue::_max_cache_size = 0; // Max cache size per queue |
pliden@6413 | 35 | |
pliden@6413 | 36 | G1StringDedupQueue::G1StringDedupQueue() : |
pliden@6413 | 37 | _cursor(0), |
pliden@6690 | 38 | _cancel(false), |
pliden@6413 | 39 | _empty(true), |
pliden@6413 | 40 | _dropped(0) { |
pliden@6413 | 41 | _nqueues = MAX2(ParallelGCThreads, (size_t)1); |
pliden@6413 | 42 | _queues = NEW_C_HEAP_ARRAY(G1StringDedupWorkerQueue, _nqueues, mtGC); |
pliden@6413 | 43 | for (size_t i = 0; i < _nqueues; i++) { |
pliden@6413 | 44 | new (_queues + i) G1StringDedupWorkerQueue(G1StringDedupWorkerQueue::default_segment_size(), _max_cache_size, _max_size); |
pliden@6413 | 45 | } |
pliden@6413 | 46 | } |
pliden@6413 | 47 | |
pliden@6413 | 48 | G1StringDedupQueue::~G1StringDedupQueue() { |
pliden@6413 | 49 | ShouldNotReachHere(); |
pliden@6413 | 50 | } |
pliden@6413 | 51 | |
pliden@6413 | 52 | void G1StringDedupQueue::create() { |
pliden@6413 | 53 | assert(_queue == NULL, "One string deduplication queue allowed"); |
pliden@6413 | 54 | _queue = new G1StringDedupQueue(); |
pliden@6413 | 55 | } |
pliden@6413 | 56 | |
pliden@6413 | 57 | void G1StringDedupQueue::wait() { |
pliden@6413 | 58 | MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); |
pliden@6690 | 59 | while (_queue->_empty && !_queue->_cancel) { |
pliden@6413 | 60 | ml.wait(Mutex::_no_safepoint_check_flag); |
pliden@6413 | 61 | } |
pliden@6413 | 62 | } |
pliden@6413 | 63 | |
pliden@6690 | 64 | void G1StringDedupQueue::cancel_wait() { |
pliden@6690 | 65 | MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); |
pliden@6690 | 66 | _queue->_cancel = true; |
pliden@6690 | 67 | ml.notify(); |
pliden@6690 | 68 | } |
pliden@6690 | 69 | |
pliden@6413 | 70 | void G1StringDedupQueue::push(uint worker_id, oop java_string) { |
pliden@6413 | 71 | assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint"); |
pliden@6413 | 72 | assert(worker_id < _queue->_nqueues, "Invalid queue"); |
pliden@6413 | 73 | |
pliden@6413 | 74 | // Push and notify waiter |
pliden@6413 | 75 | G1StringDedupWorkerQueue& worker_queue = _queue->_queues[worker_id]; |
pliden@6413 | 76 | if (!worker_queue.is_full()) { |
pliden@6413 | 77 | worker_queue.push(java_string); |
pliden@6413 | 78 | if (_queue->_empty) { |
pliden@6413 | 79 | MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); |
pliden@6413 | 80 | if (_queue->_empty) { |
pliden@6413 | 81 | // Mark non-empty and notify waiter |
pliden@6413 | 82 | _queue->_empty = false; |
pliden@6413 | 83 | ml.notify(); |
pliden@6413 | 84 | } |
pliden@6413 | 85 | } |
pliden@6413 | 86 | } else { |
pliden@6413 | 87 | // Queue is full, drop the string and update the statistics |
pliden@6413 | 88 | Atomic::inc_ptr(&_queue->_dropped); |
pliden@6413 | 89 | } |
pliden@6413 | 90 | } |
pliden@6413 | 91 | |
pliden@6413 | 92 | oop G1StringDedupQueue::pop() { |
pliden@6413 | 93 | assert(!SafepointSynchronize::is_at_safepoint(), "Must not be at safepoint"); |
pliden@6413 | 94 | No_Safepoint_Verifier nsv; |
pliden@6413 | 95 | |
pliden@6413 | 96 | // Try all queues before giving up |
pliden@6413 | 97 | for (size_t tries = 0; tries < _queue->_nqueues; tries++) { |
pliden@6413 | 98 | // The cursor indicates where we left of last time |
pliden@6413 | 99 | G1StringDedupWorkerQueue* queue = &_queue->_queues[_queue->_cursor]; |
pliden@6413 | 100 | while (!queue->is_empty()) { |
pliden@6413 | 101 | oop obj = queue->pop(); |
pliden@6413 | 102 | // The oop we pop can be NULL if it was marked |
pliden@6413 | 103 | // dead. Just ignore those and pop the next oop. |
pliden@6413 | 104 | if (obj != NULL) { |
pliden@6413 | 105 | return obj; |
pliden@6413 | 106 | } |
pliden@6413 | 107 | } |
pliden@6413 | 108 | |
pliden@6413 | 109 | // Try next queue |
pliden@6413 | 110 | _queue->_cursor = (_queue->_cursor + 1) % _queue->_nqueues; |
pliden@6413 | 111 | } |
pliden@6413 | 112 | |
pliden@6413 | 113 | // Mark empty |
pliden@6413 | 114 | _queue->_empty = true; |
pliden@6413 | 115 | |
pliden@6413 | 116 | return NULL; |
pliden@6413 | 117 | } |
pliden@6413 | 118 | |
pliden@6413 | 119 | void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl) { |
pliden@6413 | 120 | // A worker thread first claims a queue, which ensures exclusive |
pliden@6413 | 121 | // access to that queue, then continues to process it. |
pliden@6413 | 122 | for (;;) { |
pliden@6413 | 123 | // Grab next queue to scan |
pliden@6413 | 124 | size_t queue = cl->claim_queue(); |
pliden@6413 | 125 | if (queue >= _queue->_nqueues) { |
pliden@6413 | 126 | // End of queues |
pliden@6413 | 127 | break; |
pliden@6413 | 128 | } |
pliden@6413 | 129 | |
pliden@6413 | 130 | // Scan the queue |
pliden@6413 | 131 | unlink_or_oops_do(cl, queue); |
pliden@6413 | 132 | } |
pliden@6413 | 133 | } |
pliden@6413 | 134 | |
pliden@6413 | 135 | void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, size_t queue) { |
pliden@6413 | 136 | assert(queue < _queue->_nqueues, "Invalid queue"); |
pliden@6413 | 137 | StackIterator<oop, mtGC> iter(_queue->_queues[queue]); |
pliden@6413 | 138 | while (!iter.is_empty()) { |
pliden@6413 | 139 | oop* p = iter.next_addr(); |
pliden@6413 | 140 | if (*p != NULL) { |
pliden@6413 | 141 | if (cl->is_alive(*p)) { |
pliden@6413 | 142 | cl->keep_alive(p); |
pliden@6413 | 143 | } else { |
pliden@6413 | 144 | // Clear dead reference |
pliden@6413 | 145 | *p = NULL; |
pliden@6413 | 146 | } |
pliden@6413 | 147 | } |
pliden@6413 | 148 | } |
pliden@6413 | 149 | } |
pliden@6413 | 150 | |
pliden@6413 | 151 | void G1StringDedupQueue::print_statistics(outputStream* st) { |
pliden@6413 | 152 | st->print_cr( |
pliden@6413 | 153 | " [Queue]\n" |
pliden@6413 | 154 | " [Dropped: "UINTX_FORMAT"]", _queue->_dropped); |
pliden@6413 | 155 | } |
pliden@6413 | 156 | |
pliden@6413 | 157 | void G1StringDedupQueue::verify() { |
pliden@6413 | 158 | for (size_t i = 0; i < _queue->_nqueues; i++) { |
pliden@6413 | 159 | StackIterator<oop, mtGC> iter(_queue->_queues[i]); |
pliden@6413 | 160 | while (!iter.is_empty()) { |
pliden@6413 | 161 | oop obj = iter.next(); |
pliden@6413 | 162 | if (obj != NULL) { |
pliden@6413 | 163 | guarantee(Universe::heap()->is_in_reserved(obj), "Object must be on the heap"); |
pliden@6413 | 164 | guarantee(!obj->is_forwarded(), "Object must not be forwarded"); |
pliden@6413 | 165 | guarantee(java_lang_String::is_instance(obj), "Object must be a String"); |
pliden@6413 | 166 | } |
pliden@6413 | 167 | } |
pliden@6413 | 168 | } |
pliden@6413 | 169 | } |