/* * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #include "precompiled.hpp" #include "memory/archiveUtils.hpp" #include "utilities/bitMap.inline.hpp" #if INCLUDE_CDS CHeapBitMap* ArchivePtrMarker::_ptrmap = NULL; address* ArchivePtrMarker::_ptr_base; address* ArchivePtrMarker::_ptr_end; bool ArchivePtrMarker::_compacted; void ArchivePtrMarker::initialize(CHeapBitMap* ptrmap, address* ptr_base, address* ptr_end) { assert(_ptrmap == NULL, "initialize only once"); _ptr_base = ptr_base; _ptr_end = ptr_end; _compacted = false; _ptrmap = ptrmap; _ptrmap->initialize(12 * M / sizeof(intptr_t)); // default archive is about 12MB. } void ArchivePtrMarker::mark_pointer(address* ptr_loc) { assert(_ptrmap != NULL, "not initialized"); assert(!_compacted, "cannot mark anymore"); if (_ptr_base <= ptr_loc && ptr_loc < _ptr_end) { address value = *ptr_loc; if (value != NULL) { assert(uintx(ptr_loc) % sizeof(intptr_t) == 0, "pointers must be stored in aligned addresses"); size_t idx = ptr_loc - _ptr_base; if (_ptrmap->size() <= idx) { _ptrmap->resize((idx + 1) * 3 / 2); } assert(idx < _ptrmap->size(), "must be"); _ptrmap->set_bit(idx); //tty->print_cr("Marking pointer [%p] -> %p @ " SIZE_FORMAT_W(9), ptr_loc, *ptr_loc, idx); } } } class ArchivePtrBitmapCleaner: public BitMapClosure { CHeapBitMap* _ptrmap; address* _ptr_base; address _relocatable_base; address _relocatable_end; size_t _max_index; public: ArchivePtrBitmapCleaner(CHeapBitMap* ptrmap, address* ptr_base, address relocatable_base, address relocatable_end) : _ptrmap(ptrmap), _ptr_base(ptr_base), _relocatable_base(relocatable_base), _relocatable_end(relocatable_end), _max_index(0) {} bool do_bit(size_t offset) { address* ptr_loc = _ptr_base + offset; address ptr_value = *ptr_loc; if (ptr_value != NULL) { assert(_relocatable_base <= ptr_value && ptr_value < _relocatable_end, "do not point to arbitrary locations!"); if (_max_index < offset) { _max_index = offset; } } else { _ptrmap->clear_bit(offset); tty->print_cr("Clearing pointer [%p] -> %p @ " SIZE_FORMAT_W(9), ptr_loc, *ptr_loc, offset); } return true; } size_t max_index() const { return _max_index; } }; void ArchivePtrMarker::compact(address relocatable_base, address relocatable_end) { assert(!_compacted, "cannot compact again"); ArchivePtrBitmapCleaner cleaner(_ptrmap, _ptr_base, relocatable_base, relocatable_end); _ptrmap->iterate(&cleaner); _ptrmap->resize(cleaner.max_index() + 1); _compacted = true; } #endif // INCLUDE_CDS