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()) return NULL; 124 _alloc_next--; 125 return *_alloc_next; 126 } 127 }; 128 129 // Implements storage for a set of code roots. 130 // All methods that modify the set are not thread-safe except if otherwise noted. 131 class G1CodeRootSet { 132 private: 133 // Global free chunk list management 134 static FreeList<G1CodeRootChunk> _free_list; 135 // Total number of chunks handed out 136 static size_t _num_chunks_handed_out; 137 138 static G1CodeRootChunk* new_chunk(); 139 static void free_chunk(G1CodeRootChunk* chunk); 140 // Free all elements of the given list. 141 static void free_all_chunks(FreeList<G1CodeRootChunk>* list); 142 143 // Return the chunk that contains the given nmethod, NULL otherwise. 144 // Scans the list of chunks backwards, as this method is used to add new 145 // entries, which are typically added in bulk for a single nmethod. 146 G1CodeRootChunk* find(nmethod* method); 147 void free(G1CodeRootChunk* chunk); 148 149 size_t _length; 150 FreeList<G1CodeRootChunk> _list; 151 152 public: 153 G1CodeRootSet(); 154 ~G1CodeRootSet(); 155 156 static void initialize(); 157 static void purge_chunks(size_t keep_ratio); 158 159 static size_t static_mem_size(); 160 static size_t fl_mem_size(); 161 162 // Search for the code blob from the RHS to avoid 163 // duplicate entries as much as possible. 164 void add(nmethod* method); 165 166 void remove(nmethod* method); 167 nmethod* pop(); 168 169 bool contains(nmethod* method); 170 171 void clear(); 172 173 void nmethods_do(CodeBlobClosure* blk); 174 175 bool is_empty() { return length() == 0; } 176 177 // Length in elements 178 size_t length() const { return _length; } 179 180 // Memory size in bytes taken by this set. 181 size_t mem_size(); 182 }; 183 184 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP