1/*
2 * Copyright (c) 2017, 2019, 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#include "precompiled.hpp"
26#include "memory/metaspaceClosure.hpp"
27
28// Update the reference to point to new_loc.
29void MetaspaceClosure::Ref::update(address new_loc) const {
30 log_trace(cds)("Ref: [" PTR_FORMAT "] -> " PTR_FORMAT " => " PTR_FORMAT,
31 p2i(mpp()), p2i(obj()), p2i(new_loc));
32 uintx p = (uintx)new_loc;
33 p |= flag_bits(); // Make sure the flag bits are copied to the new pointer.
34 *(address*)mpp() = (address)p;
35}
36
37void MetaspaceClosure::push_impl(MetaspaceClosure::Ref* ref) {
38 if (_nest_level < MAX_NEST_LEVEL) {
39 do_push(ref);
40 delete ref;
41 } else {
42 ref->set_next(_pending_refs);
43 _pending_refs = ref;
44 }
45}
46
47void MetaspaceClosure::do_push(MetaspaceClosure::Ref* ref) {
48 if (ref->not_null()) {
49 bool read_only;
50 Writability w = ref->writability();
51 switch (w) {
52 case _writable:
53 read_only = false;
54 break;
55 case _not_writable:
56 read_only = true;
57 break;
58 default:
59 assert(w == _default, "must be");
60 read_only = ref->is_read_only_by_default();
61 }
62 _nest_level ++;
63 if (do_ref(ref, read_only)) { // true means we want to iterate the embedded pointer in <ref>
64 ref->metaspace_pointers_do(this);
65 }
66 _nest_level --;
67 }
68}
69
70void MetaspaceClosure::finish() {
71 assert(_nest_level == 0, "must be");
72 while (_pending_refs != NULL) {
73 Ref* ref = _pending_refs;
74 _pending_refs = _pending_refs->next();
75 do_push(ref);
76 delete ref;
77 }
78}
79
80MetaspaceClosure::~MetaspaceClosure() {
81 assert(_pending_refs == NULL,
82 "you must explicitly call MetaspaceClosure::finish() to process all refs!");
83}
84
85bool UniqueMetaspaceClosure::do_ref(MetaspaceClosure::Ref* ref, bool read_only) {
86 bool* found = _has_been_visited.lookup(ref->obj());
87 if (found != NULL) {
88 assert(*found == read_only, "must be");
89 return false; // Already visited: no need to iterate embedded pointers.
90 } else {
91 _has_been_visited.add(ref->obj(), read_only);
92 if (_has_been_visited.maybe_grow(MAX_TABLE_SIZE)) {
93 log_info(cds, hashtables)("Expanded _has_been_visited table to %d", _has_been_visited.table_size());
94 }
95 return do_unique_ref(ref, read_only);
96 }
97}
98