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 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP 26 #define SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP 27 28 #include "memory/allocation.hpp" 29 #include "memory/freeList.hpp" 30 #include "runtime/globals.hpp" 31 32 class CodeBlobClosure; 33 34 // The elements of the G1CodeRootChunk is either: 35 // 1) nmethod pointers 36 // 2) nodes in an internally chained free list 37 typedef union { 38 nmethod* _nmethod; 39 void* _link; 40 } NmethodOrLink; 41 42 class G1CodeRootChunk : public CHeapObj<mtGC> { 43 private: 44 static const int NUM_ENTRIES = 32; 45 public: 46 G1CodeRootChunk* _next; 47 G1CodeRootChunk* _prev; 48 49 NmethodOrLink* _top; 50 // First free position within the chunk. 51 volatile NmethodOrLink* _free; 52 53 NmethodOrLink _data[NUM_ENTRIES]; 54 55 NmethodOrLink* bottom() const { 56 return (NmethodOrLink*) &(_data[0]); 57 } 58 59 NmethodOrLink* end() const { 60 return (NmethodOrLink*) &(_data[NUM_ENTRIES]); 61 } 62 63 bool is_link(NmethodOrLink* nmethod_or_link) { 64 return nmethod_or_link->_link == NULL || 65 (bottom() <= nmethod_or_link->_link 66 && nmethod_or_link->_link < end()); 67 } 68 69 bool is_nmethod(NmethodOrLink* nmethod_or_link) { 70 return !is_link(nmethod_or_link); 71 } 72 73 public: 74 G1CodeRootChunk(); 75 ~G1CodeRootChunk() {} 76 77 static size_t word_size() { return (size_t)(align_size_up_(sizeof(G1CodeRootChunk), HeapWordSize) / HeapWordSize); } 78 79 // FreeList "interface" methods 80 81 G1CodeRootChunk* next() const { return _next; } 82 G1CodeRootChunk* prev() const { return _prev; } 83 void set_next(G1CodeRootChunk* v) { _next = v; assert(v != this, "Boom");} 84 void set_prev(G1CodeRootChunk* v) { _prev = v; assert(v != this, "Boom");} 85 void clear_next() { set_next(NULL); } 86 void clear_prev() { set_prev(NULL); } 87 88 size_t size() const { return word_size(); } 89 90 void link_next(G1CodeRootChunk* ptr) { set_next(ptr); } 91 void link_prev(G1CodeRootChunk* ptr) { set_prev(ptr); } 92 void link_after(G1CodeRootChunk* ptr) { 93 link_next(ptr); 94 if (ptr != NULL) ptr->link_prev((G1CodeRootChunk*)this); 95 } 96 97 bool is_free() { return true; } 98 99 // New G1CodeRootChunk routines 100 101 void reset(); 102 103 bool is_empty() const { 104 return _top == bottom(); 105 } 106 107 bool is_full() const { 108 return _top == end() && _free == NULL; 109 } 110 111 bool contains(nmethod* method) { 112 NmethodOrLink* cur = bottom(); 113 while (cur != _top) { 114 if (cur->_nmethod == method) return true; 115 cur++; 116 } 117 return false; 118 } 119 120 bool add(nmethod* method) { 121 if (is_full()) { 122 return false; 123 } 124 125 if (_free != NULL) { 126 // Take from internally chained free list 127 NmethodOrLink* first_free = (NmethodOrLink*)_free; 128 _free = (NmethodOrLink*)_free->_link; 129 first_free->_nmethod = method; 130 } else { 131 // Take from top. 132 _top->_nmethod = method; 133 _top++; 134 } 135 136 return true; 137 } 138 139 bool remove_lock_free(nmethod* method); 140 141 void nmethods_do(CodeBlobClosure* blk); 142 143 nmethod* pop() { 144 if (_free != NULL) { 145 // Kill the free list. 146 _free = NULL; 147 } 148 149 while (!is_empty()) { 150 _top--; 151 if (is_nmethod(_top)) { 152 return _top->_nmethod; 153 } 154 } 155 156 return NULL; 157 } 158 }; 159 160 // Manages free chunks. 161 class G1CodeRootChunkManager VALUE_OBJ_CLASS_SPEC { 162 private: 163 // Global free chunk list management 164 FreeList<G1CodeRootChunk> _free_list; 165 // Total number of chunks handed out 166 size_t _num_chunks_handed_out; 167 168 public: 169 G1CodeRootChunkManager(); 170 171 G1CodeRootChunk* new_chunk(); 172 void free_chunk(G1CodeRootChunk* chunk); 173 // Free all elements of the given list. 174 void free_all_chunks(FreeList<G1CodeRootChunk>* list); 175 176 void initialize(); 177 void purge_chunks(size_t keep_ratio); 178 179 static size_t static_mem_size(); 180 size_t fl_mem_size(); 181 182 #ifndef PRODUCT 183 size_t num_chunks_handed_out() const; 184 size_t num_free_chunks() const; 185 #endif 186 }; 187 188 // Implements storage for a set of code roots. 189 // All methods that modify the set are not thread-safe except if otherwise noted. 190 class G1CodeRootSet VALUE_OBJ_CLASS_SPEC { 191 private: 192 // Global default free chunk manager instance. 193 static G1CodeRootChunkManager _default_chunk_manager; 194 195 G1CodeRootChunk* new_chunk() { return _manager->new_chunk(); } 196 void free_chunk(G1CodeRootChunk* chunk) { _manager->free_chunk(chunk); } 197 // Free all elements of the given list. 198 void free_all_chunks(FreeList<G1CodeRootChunk>* list) { _manager->free_all_chunks(list); } 199 200 // Return the chunk that contains the given nmethod, NULL otherwise. 201 // Scans the list of chunks backwards, as this method is used to add new 202 // entries, which are typically added in bulk for a single nmethod. 203 G1CodeRootChunk* find(nmethod* method); 204 void free(G1CodeRootChunk* chunk); 205 206 size_t _length; 207 FreeList<G1CodeRootChunk> _list; 208 G1CodeRootChunkManager* _manager; 209 210 public: 211 // If an instance is initialized with a chunk manager of NULL, use the global 212 // default one. 213 G1CodeRootSet(G1CodeRootChunkManager* manager = NULL); 214 ~G1CodeRootSet(); 215 216 static void purge_chunks(size_t keep_ratio); 217 218 static size_t free_chunks_static_mem_size(); 219 static size_t free_chunks_mem_size(); 220 221 // Search for the code blob from the recently allocated ones to find duplicates more quickly, as this 222 // method is likely to be repeatedly called with the same nmethod. 223 void add(nmethod* method); 224 225 void remove_lock_free(nmethod* method); 226 nmethod* pop(); 227 228 bool contains(nmethod* method); 229 230 void clear(); 231 232 void nmethods_do(CodeBlobClosure* blk) const; 233 234 bool is_empty() { return length() == 0; } 235 236 // Length in elements 237 size_t length() const { return _length; } 238 239 // Static data memory size in bytes of this set. 240 static size_t static_mem_size(); 241 // Memory size in bytes taken by this set. 242 size_t mem_size(); 243 244 static void test() PRODUCT_RETURN; 245 }; 246 247 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP