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