aoqi@0: /* aoqi@0: * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP aoqi@0: #define SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP aoqi@0: aoqi@0: #include "memory/allocation.hpp" aoqi@0: #include "memory/freeList.hpp" aoqi@0: #include "runtime/globals.hpp" aoqi@0: aoqi@0: class CodeBlobClosure; aoqi@0: stefank@6992: // The elements of the G1CodeRootChunk is either: stefank@6992: // 1) nmethod pointers stefank@6992: // 2) nodes in an internally chained free list stefank@6992: typedef union { stefank@6992: nmethod* _nmethod; stefank@6992: void* _link; stefank@6992: } NmethodOrLink; stefank@6992: aoqi@0: class G1CodeRootChunk : public CHeapObj { aoqi@0: private: aoqi@0: static const int NUM_ENTRIES = 32; aoqi@0: public: aoqi@0: G1CodeRootChunk* _next; aoqi@0: G1CodeRootChunk* _prev; aoqi@0: stefank@6992: NmethodOrLink* _top; stefank@6992: // First free position within the chunk. stefank@6992: volatile NmethodOrLink* _free; aoqi@0: stefank@6992: NmethodOrLink _data[NUM_ENTRIES]; aoqi@0: stefank@6992: NmethodOrLink* bottom() const { stefank@6992: return (NmethodOrLink*) &(_data[0]); aoqi@0: } aoqi@0: stefank@6992: NmethodOrLink* end() const { stefank@6992: return (NmethodOrLink*) &(_data[NUM_ENTRIES]); stefank@6992: } stefank@6992: stefank@6992: bool is_link(NmethodOrLink* nmethod_or_link) { stefank@6992: return nmethod_or_link->_link == NULL || stefank@6992: (bottom() <= nmethod_or_link->_link stefank@6992: && nmethod_or_link->_link < end()); stefank@6992: } stefank@6992: stefank@6992: bool is_nmethod(NmethodOrLink* nmethod_or_link) { stefank@6992: return !is_link(nmethod_or_link); aoqi@0: } aoqi@0: aoqi@0: public: aoqi@0: G1CodeRootChunk(); aoqi@0: ~G1CodeRootChunk() {} aoqi@0: aoqi@0: static size_t word_size() { return (size_t)(align_size_up_(sizeof(G1CodeRootChunk), HeapWordSize) / HeapWordSize); } aoqi@0: aoqi@0: // FreeList "interface" methods aoqi@0: aoqi@0: G1CodeRootChunk* next() const { return _next; } aoqi@0: G1CodeRootChunk* prev() const { return _prev; } aoqi@0: void set_next(G1CodeRootChunk* v) { _next = v; assert(v != this, "Boom");} aoqi@0: void set_prev(G1CodeRootChunk* v) { _prev = v; assert(v != this, "Boom");} aoqi@0: void clear_next() { set_next(NULL); } aoqi@0: void clear_prev() { set_prev(NULL); } aoqi@0: aoqi@0: size_t size() const { return word_size(); } aoqi@0: aoqi@0: void link_next(G1CodeRootChunk* ptr) { set_next(ptr); } aoqi@0: void link_prev(G1CodeRootChunk* ptr) { set_prev(ptr); } aoqi@0: void link_after(G1CodeRootChunk* ptr) { aoqi@0: link_next(ptr); aoqi@0: if (ptr != NULL) ptr->link_prev((G1CodeRootChunk*)this); aoqi@0: } aoqi@0: aoqi@0: bool is_free() { return true; } aoqi@0: aoqi@0: // New G1CodeRootChunk routines aoqi@0: aoqi@0: void reset(); aoqi@0: aoqi@0: bool is_empty() const { aoqi@0: return _top == bottom(); aoqi@0: } aoqi@0: aoqi@0: bool is_full() const { stefank@6992: return _top == end() && _free == NULL; aoqi@0: } aoqi@0: aoqi@0: bool contains(nmethod* method) { stefank@6992: NmethodOrLink* cur = bottom(); aoqi@0: while (cur != _top) { stefank@6992: if (cur->_nmethod == method) return true; aoqi@0: cur++; aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: bool add(nmethod* method) { stefank@6992: if (is_full()) { stefank@6992: return false; stefank@6992: } stefank@6992: stefank@6992: if (_free != NULL) { stefank@6992: // Take from internally chained free list stefank@6992: NmethodOrLink* first_free = (NmethodOrLink*)_free; stefank@6992: _free = (NmethodOrLink*)_free->_link; stefank@6992: first_free->_nmethod = method; stefank@6992: } else { stefank@6992: // Take from top. stefank@6992: _top->_nmethod = method; stefank@6992: _top++; stefank@6992: } stefank@6992: aoqi@0: return true; aoqi@0: } aoqi@0: stefank@6992: bool remove_lock_free(nmethod* method); aoqi@0: aoqi@0: void nmethods_do(CodeBlobClosure* blk); aoqi@0: aoqi@0: nmethod* pop() { stefank@6992: if (_free != NULL) { stefank@6992: // Kill the free list. stefank@6992: _free = NULL; aoqi@0: } stefank@6992: stefank@6992: while (!is_empty()) { stefank@6992: _top--; stefank@6992: if (is_nmethod(_top)) { stefank@6992: return _top->_nmethod; stefank@6992: } stefank@6992: } stefank@6992: stefank@6992: return NULL; aoqi@0: } aoqi@0: }; aoqi@0: tschatzl@6925: // Manages free chunks. tschatzl@6925: class G1CodeRootChunkManager VALUE_OBJ_CLASS_SPEC { tschatzl@6925: private: tschatzl@6925: // Global free chunk list management tschatzl@6925: FreeList _free_list; tschatzl@6925: // Total number of chunks handed out tschatzl@6925: size_t _num_chunks_handed_out; tschatzl@6925: tschatzl@6925: public: tschatzl@6925: G1CodeRootChunkManager(); tschatzl@6925: tschatzl@6925: G1CodeRootChunk* new_chunk(); tschatzl@6925: void free_chunk(G1CodeRootChunk* chunk); tschatzl@6925: // Free all elements of the given list. tschatzl@6925: void free_all_chunks(FreeList* list); tschatzl@6925: tschatzl@6925: void initialize(); tschatzl@6925: void purge_chunks(size_t keep_ratio); tschatzl@6925: tschatzl@6932: static size_t static_mem_size(); tschatzl@6925: size_t fl_mem_size(); tschatzl@6925: tschatzl@6925: #ifndef PRODUCT tschatzl@6925: size_t num_chunks_handed_out() const; tschatzl@6925: size_t num_free_chunks() const; tschatzl@6925: #endif tschatzl@6925: }; tschatzl@6925: aoqi@0: // Implements storage for a set of code roots. aoqi@0: // All methods that modify the set are not thread-safe except if otherwise noted. aoqi@0: class G1CodeRootSet VALUE_OBJ_CLASS_SPEC { aoqi@0: private: tschatzl@6925: // Global default free chunk manager instance. tschatzl@6925: static G1CodeRootChunkManager _default_chunk_manager; aoqi@0: tschatzl@6925: G1CodeRootChunk* new_chunk() { return _manager->new_chunk(); } tschatzl@6925: void free_chunk(G1CodeRootChunk* chunk) { _manager->free_chunk(chunk); } aoqi@0: // Free all elements of the given list. tschatzl@6925: void free_all_chunks(FreeList* list) { _manager->free_all_chunks(list); } aoqi@0: aoqi@0: // Return the chunk that contains the given nmethod, NULL otherwise. aoqi@0: // Scans the list of chunks backwards, as this method is used to add new aoqi@0: // entries, which are typically added in bulk for a single nmethod. aoqi@0: G1CodeRootChunk* find(nmethod* method); aoqi@0: void free(G1CodeRootChunk* chunk); aoqi@0: aoqi@0: size_t _length; aoqi@0: FreeList _list; tschatzl@6925: G1CodeRootChunkManager* _manager; aoqi@0: aoqi@0: public: tschatzl@6925: // If an instance is initialized with a chunk manager of NULL, use the global tschatzl@6925: // default one. tschatzl@6925: G1CodeRootSet(G1CodeRootChunkManager* manager = NULL); aoqi@0: ~G1CodeRootSet(); aoqi@0: aoqi@0: static void purge_chunks(size_t keep_ratio); aoqi@0: tschatzl@6932: static size_t free_chunks_static_mem_size(); tschatzl@6925: static size_t free_chunks_mem_size(); aoqi@0: aoqi@0: // Search for the code blob from the recently allocated ones to find duplicates more quickly, as this aoqi@0: // method is likely to be repeatedly called with the same nmethod. aoqi@0: void add(nmethod* method); aoqi@0: stefank@6992: void remove_lock_free(nmethod* method); aoqi@0: nmethod* pop(); aoqi@0: aoqi@0: bool contains(nmethod* method); aoqi@0: aoqi@0: void clear(); aoqi@0: aoqi@0: void nmethods_do(CodeBlobClosure* blk) const; aoqi@0: aoqi@0: bool is_empty() { return length() == 0; } aoqi@0: aoqi@0: // Length in elements aoqi@0: size_t length() const { return _length; } aoqi@0: tschatzl@6932: // Static data memory size in bytes of this set. tschatzl@6932: static size_t static_mem_size(); aoqi@0: // Memory size in bytes taken by this set. aoqi@0: size_t mem_size(); aoqi@0: aoqi@0: static void test() PRODUCT_RETURN; aoqi@0: }; aoqi@0: aoqi@0: #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP