28 #include "gc_implementation/g1/g1CodeCacheRemSet.hpp" |
28 #include "gc_implementation/g1/g1CodeCacheRemSet.hpp" |
29 #include "memory/iterator.hpp" |
29 #include "memory/iterator.hpp" |
30 |
30 |
31 PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC |
31 PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC |
32 |
32 |
33 G1CodeRootChunk::G1CodeRootChunk() : _top(NULL), _next(NULL), _prev(NULL) { |
33 G1CodeRootChunk::G1CodeRootChunk() : _top(NULL), _next(NULL), _prev(NULL), _free(NULL) { |
34 _top = bottom(); |
34 _top = bottom(); |
35 } |
35 } |
36 |
36 |
37 void G1CodeRootChunk::reset() { |
37 void G1CodeRootChunk::reset() { |
38 _next = _prev = NULL; |
38 _next = _prev = NULL; |
|
39 _free = NULL; |
39 _top = bottom(); |
40 _top = bottom(); |
40 } |
41 } |
41 |
42 |
42 void G1CodeRootChunk::nmethods_do(CodeBlobClosure* cl) { |
43 void G1CodeRootChunk::nmethods_do(CodeBlobClosure* cl) { |
43 nmethod** cur = bottom(); |
44 NmethodOrLink* cur = bottom(); |
44 while (cur != _top) { |
45 while (cur != _top) { |
45 cl->do_code_blob(*cur); |
46 if (is_nmethod(cur)) { |
|
47 cl->do_code_blob(cur->_nmethod); |
|
48 } |
46 cur++; |
49 cur++; |
47 } |
50 } |
|
51 } |
|
52 |
|
53 bool G1CodeRootChunk::remove_lock_free(nmethod* method) { |
|
54 NmethodOrLink* cur = bottom(); |
|
55 |
|
56 for (NmethodOrLink* cur = bottom(); cur != _top; cur++) { |
|
57 if (cur->_nmethod == method) { |
|
58 bool result = Atomic::cmpxchg_ptr(NULL, &cur->_nmethod, method) == method; |
|
59 |
|
60 if (!result) { |
|
61 // Someone else cleared out this entry. |
|
62 return false; |
|
63 } |
|
64 |
|
65 // The method was cleared. Time to link it into the free list. |
|
66 NmethodOrLink* prev_free; |
|
67 do { |
|
68 prev_free = (NmethodOrLink*)_free; |
|
69 cur->_link = prev_free; |
|
70 } while (Atomic::cmpxchg_ptr(cur, &_free, prev_free) != prev_free); |
|
71 |
|
72 return true; |
|
73 } |
|
74 } |
|
75 |
|
76 return false; |
48 } |
77 } |
49 |
78 |
50 G1CodeRootChunkManager::G1CodeRootChunkManager() : _free_list(), _num_chunks_handed_out(0) { |
79 G1CodeRootChunkManager::G1CodeRootChunkManager() : _free_list(), _num_chunks_handed_out(0) { |
51 _free_list.initialize(); |
80 _free_list.initialize(); |
52 _free_list.set_size(G1CodeRootChunk::word_size()); |
81 _free_list.set_size(G1CodeRootChunk::word_size()); |
138 clear(); |
167 clear(); |
139 } |
168 } |
140 |
169 |
141 void G1CodeRootSet::add(nmethod* method) { |
170 void G1CodeRootSet::add(nmethod* method) { |
142 if (!contains(method)) { |
171 if (!contains(method)) { |
143 // Try to add the nmethod. If there is not enough space, get a new chunk. |
172 // Find the first chunk thatisn't full. |
144 if (_list.head() == NULL || _list.head()->is_full()) { |
173 G1CodeRootChunk* cur = _list.head(); |
145 G1CodeRootChunk* cur = new_chunk(); |
174 while (cur != NULL) { |
|
175 if (!cur->is_full()) { |
|
176 break; |
|
177 } |
|
178 cur = cur->next(); |
|
179 } |
|
180 |
|
181 // All chunks are full, get a new chunk. |
|
182 if (cur == NULL) { |
|
183 cur = new_chunk(); |
146 _list.return_chunk_at_head(cur); |
184 _list.return_chunk_at_head(cur); |
147 } |
185 } |
148 bool result = _list.head()->add(method); |
186 |
|
187 // Add the nmethod. |
|
188 bool result = cur->add(method); |
|
189 |
149 guarantee(result, err_msg("Not able to add nmethod "PTR_FORMAT" to newly allocated chunk.", method)); |
190 guarantee(result, err_msg("Not able to add nmethod "PTR_FORMAT" to newly allocated chunk.", method)); |
|
191 |
150 _length++; |
192 _length++; |
151 } |
193 } |
152 } |
194 } |
153 |
195 |
154 void G1CodeRootSet::remove(nmethod* method) { |
196 void G1CodeRootSet::remove_lock_free(nmethod* method) { |
155 G1CodeRootChunk* found = find(method); |
197 G1CodeRootChunk* found = find(method); |
156 if (found != NULL) { |
198 if (found != NULL) { |
157 bool result = found->remove(method); |
199 bool result = found->remove_lock_free(method); |
158 guarantee(result, err_msg("could not find nmethod "PTR_FORMAT" during removal although we previously found it", method)); |
200 if (result) { |
159 // eventually free completely emptied chunk |
201 Atomic::dec_ptr((volatile intptr_t*)&_length); |
160 if (found->is_empty()) { |
202 } |
161 _list.remove_chunk(found); |
|
162 free(found); |
|
163 } |
|
164 _length--; |
|
165 } |
203 } |
166 assert(!contains(method), err_msg(PTR_FORMAT" still contains nmethod "PTR_FORMAT, this, method)); |
204 assert(!contains(method), err_msg(PTR_FORMAT" still contains nmethod "PTR_FORMAT, this, method)); |
167 } |
205 } |
168 |
206 |
169 nmethod* G1CodeRootSet::pop() { |
207 nmethod* G1CodeRootSet::pop() { |
170 do { |
208 while (true) { |
171 G1CodeRootChunk* cur = _list.head(); |
209 G1CodeRootChunk* cur = _list.head(); |
172 if (cur == NULL) { |
210 if (cur == NULL) { |
173 assert(_length == 0, "when there are no chunks, there should be no elements"); |
211 assert(_length == 0, "when there are no chunks, there should be no elements"); |
174 return NULL; |
212 return NULL; |
175 } |
213 } |