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. |
29 | void 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 | |
37 | void 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 | |
47 | void 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 | |
70 | void 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 | |
80 | MetaspaceClosure::~MetaspaceClosure() { |
81 | assert(_pending_refs == NULL, |
82 | "you must explicitly call MetaspaceClosure::finish() to process all refs!" ); |
83 | } |
84 | |
85 | bool 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 | |