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 class G1CodeRootChunk : public CHeapObj<mtGC> { 35 private: 36 static const int num_entries = 32; 37 public: 38 G1CodeRootChunk* _next; 39 G1CodeRootChunk* _prev; 40 41 nmethod** _alloc_next; 42 43 nmethod* _data[num_entries]; 44 45 nmethod** first_element() const { 46 return (nmethod**) &(_data[0]); 47 } 48 49 nmethod** top() const { 50 return (nmethod**) &(_data[num_entries]); 51 } 52 53 public: 54 G1CodeRootChunk(); 55 ~G1CodeRootChunk() {} 56 57 static size_t word_size() { return (size_t)(align_size_up_(sizeof(G1CodeRootChunk), HeapWordSize) / HeapWordSize); } 58 59 // FreeList "interface" methods 60 61 G1CodeRootChunk* next() const { return _next; } 62 G1CodeRootChunk* prev() const { return _prev; } 63 void set_next(G1CodeRootChunk* v) { _next = v; assert(v != this, "Boom");} 64 void set_prev(G1CodeRootChunk* v) { _prev = v; assert(v != this, "Boom");} 65 void clear_next() { set_next(NULL); } 66 void clear_prev() { set_prev(NULL); } 67 68 size_t size() const volatile { return word_size(); } 69 70 void link_next(G1CodeRootChunk* ptr) { set_next(ptr); } 71 void link_prev(G1CodeRootChunk* ptr) { set_prev(ptr); } 72 void link_after(G1CodeRootChunk* ptr) { 73 link_next(ptr); 74 if (ptr != NULL) ptr->link_prev((G1CodeRootChunk*)this); 75 } 76 77 bool is_free() { return true; } 78 79 // New G1CodeRootChunk routines 80 81 void reset(); 82 83 bool is_empty() const { 84 return _alloc_next == first_element(); 85 } 86 87 bool is_full() const { 88 return _alloc_next == (nmethod**)top(); 89 } 90 91 bool find(nmethod* method) { 92 nmethod** cur = first_element(); 93 while (cur != _alloc_next) { 94 if (*cur == method) return true; 95 cur++; 96 } 97 return false; 98 } 99 100 bool add(nmethod* method) { 101 if (is_full()) return false; 102 *_alloc_next = method; 103 _alloc_next++; 104 return true; 105 } 106 107 bool remove(nmethod* method) { 108 nmethod** cur = first_element(); 109 while (cur != _alloc_next) { 110 if (*cur == method) { 111 memmove(cur, cur + 1, (_alloc_next - (cur + 1)) * sizeof(nmethod**)); 112 _alloc_next--; 113 return true; 114 } 115 cur++; 116 } 117 return false; 118 } 119 120 void nmethods_do(CodeBlobClosure* blk); 121 122 nmethod* pop() { 123 if (is_empty()) { 124 return NULL; 125 } 126 _alloc_next--; 127 return *_alloc_next; 128 } 129 }; 130 131 // Implements storage for a set of code roots. 132 // All methods that modify the set are not thread-safe except if otherwise noted. 133 class G1CodeRootSet { 134 private: 135 // Global free chunk list management 136 static FreeList<G1CodeRootChunk> _free_list; 137 // Total number of chunks handed out 138 static size_t _num_chunks_handed_out; 139 140 static G1CodeRootChunk* new_chunk(); 141 static void free_chunk(G1CodeRootChunk* chunk); 142 // Free all elements of the given list. 143 static void free_all_chunks(FreeList<G1CodeRootChunk>* list); 144 145 // Return the chunk that contains the given nmethod, NULL otherwise. 146 // Scans the list of chunks backwards, as this method is used to add new 147 // entries, which are typically added in bulk for a single nmethod. 148 G1CodeRootChunk* find(nmethod* method); 149 void free(G1CodeRootChunk* chunk); 150 151 size_t _length; 152 FreeList<G1CodeRootChunk> _list; 153 154 public: 155 G1CodeRootSet(); 156 ~G1CodeRootSet(); 157 158 static void initialize(); 159 static void purge_chunks(size_t keep_ratio); 160 161 static size_t static_mem_size(); 162 static size_t fl_mem_size(); 163 164 // Search for the code blob from the recently allocated ones to find duplicates more quickly, as this 165 // method is likely to be repeatedly called with the same nmethod. 166 void add(nmethod* method); 167 168 void remove(nmethod* method); 169 nmethod* pop(); 170 171 bool contains(nmethod* method); 172 173 void clear(); 174 175 void nmethods_do(CodeBlobClosure* blk) const; 176 177 bool is_empty() { return length() == 0; } 178 179 // Length in elements 180 size_t length() const { return _length; } 181 182 // Memory size in bytes taken by this set. 183 size_t mem_size(); 184 }; 185 186 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP