1/*
2 * Copyright (c) 2015, 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#ifndef SHARE_OOPS_INSTANCEREFKLASS_INLINE_HPP
26#define SHARE_OOPS_INSTANCEREFKLASS_INLINE_HPP
27
28#include "classfile/javaClasses.inline.hpp"
29#include "gc/shared/referenceProcessor.hpp"
30#include "logging/log.hpp"
31#include "oops/access.inline.hpp"
32#include "oops/instanceKlass.inline.hpp"
33#include "oops/instanceRefKlass.hpp"
34#include "oops/oop.inline.hpp"
35#include "utilities/debug.hpp"
36#include "utilities/globalDefinitions.hpp"
37#include "utilities/macros.hpp"
38
39template <typename T, class OopClosureType, class Contains>
40void InstanceRefKlass::do_referent(oop obj, OopClosureType* closure, Contains& contains) {
41 T* referent_addr = (T*)java_lang_ref_Reference::referent_addr_raw(obj);
42 if (contains(referent_addr)) {
43 Devirtualizer::do_oop(closure, referent_addr);
44 }
45}
46
47template <typename T, class OopClosureType, class Contains>
48void InstanceRefKlass::do_discovered(oop obj, OopClosureType* closure, Contains& contains) {
49 T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr_raw(obj);
50 if (contains(discovered_addr)) {
51 Devirtualizer::do_oop(closure, discovered_addr);
52 }
53}
54
55static inline oop load_referent(oop obj, ReferenceType type) {
56 if (type == REF_PHANTOM) {
57 return HeapAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(java_lang_ref_Reference::referent_addr_raw(obj));
58 } else {
59 return HeapAccess<ON_WEAK_OOP_REF | AS_NO_KEEPALIVE>::oop_load(java_lang_ref_Reference::referent_addr_raw(obj));
60 }
61}
62
63template <typename T, class OopClosureType>
64bool InstanceRefKlass::try_discover(oop obj, ReferenceType type, OopClosureType* closure) {
65 ReferenceDiscoverer* rd = closure->ref_discoverer();
66 if (rd != NULL) {
67 oop referent = load_referent(obj, type);
68 if (referent != NULL) {
69 if (!referent->is_gc_marked()) {
70 // Only try to discover if not yet marked.
71 return rd->discover_reference(obj, type);
72 }
73 }
74 }
75 return false;
76}
77
78template <typename T, class OopClosureType, class Contains>
79void InstanceRefKlass::oop_oop_iterate_discovery(oop obj, ReferenceType type, OopClosureType* closure, Contains& contains) {
80 // Try to discover reference and return if it succeeds.
81 if (try_discover<T>(obj, type, closure)) {
82 return;
83 }
84
85 // Treat referent and discovered as normal oops.
86 do_referent<T>(obj, closure, contains);
87 do_discovered<T>(obj, closure, contains);
88}
89
90template <typename T, class OopClosureType, class Contains>
91void InstanceRefKlass::oop_oop_iterate_discovered_and_discovery(oop obj, ReferenceType type, OopClosureType* closure, Contains& contains) {
92 // Explicitly apply closure to the discovered field.
93 do_discovered<T>(obj, closure, contains);
94 // Then do normal reference processing with discovery.
95 oop_oop_iterate_discovery<T>(obj, type, closure, contains);
96}
97
98template <typename T, class OopClosureType, class Contains>
99void InstanceRefKlass::oop_oop_iterate_fields(oop obj, OopClosureType* closure, Contains& contains) {
100 assert(closure->ref_discoverer() == NULL, "ReferenceDiscoverer should not be set");
101 do_referent<T>(obj, closure, contains);
102 do_discovered<T>(obj, closure, contains);
103}
104
105template <typename T, class OopClosureType, class Contains>
106void InstanceRefKlass::oop_oop_iterate_fields_except_referent(oop obj, OopClosureType* closure, Contains& contains) {
107 assert(closure->ref_discoverer() == NULL, "ReferenceDiscoverer should not be set");
108 do_discovered<T>(obj, closure, contains);
109}
110
111template <typename T, class OopClosureType, class Contains>
112void InstanceRefKlass::oop_oop_iterate_ref_processing(oop obj, OopClosureType* closure, Contains& contains) {
113 switch (closure->reference_iteration_mode()) {
114 case OopIterateClosure::DO_DISCOVERY:
115 trace_reference_gc<T>("do_discovery", obj);
116 oop_oop_iterate_discovery<T>(obj, reference_type(), closure, contains);
117 break;
118 case OopIterateClosure::DO_DISCOVERED_AND_DISCOVERY:
119 trace_reference_gc<T>("do_discovered_and_discovery", obj);
120 oop_oop_iterate_discovered_and_discovery<T>(obj, reference_type(), closure, contains);
121 break;
122 case OopIterateClosure::DO_FIELDS:
123 trace_reference_gc<T>("do_fields", obj);
124 oop_oop_iterate_fields<T>(obj, closure, contains);
125 break;
126 case OopIterateClosure::DO_FIELDS_EXCEPT_REFERENT:
127 trace_reference_gc<T>("do_fields_except_referent", obj);
128 oop_oop_iterate_fields_except_referent<T>(obj, closure, contains);
129 break;
130 default:
131 ShouldNotReachHere();
132 }
133}
134
135class AlwaysContains {
136 public:
137 template <typename T> bool operator()(T* p) const { return true; }
138};
139
140template <typename T, class OopClosureType>
141void InstanceRefKlass::oop_oop_iterate_ref_processing(oop obj, OopClosureType* closure) {
142 AlwaysContains always_contains;
143 oop_oop_iterate_ref_processing<T>(obj, closure, always_contains);
144}
145
146class MrContains {
147 const MemRegion _mr;
148 public:
149 MrContains(MemRegion mr) : _mr(mr) {}
150 template <typename T> bool operator()(T* p) const { return _mr.contains(p); }
151};
152
153template <typename T, class OopClosureType>
154void InstanceRefKlass::oop_oop_iterate_ref_processing_bounded(oop obj, OopClosureType* closure, MemRegion mr) {
155 const MrContains contains(mr);
156 oop_oop_iterate_ref_processing<T>(obj, closure, contains);
157}
158
159template <typename T, class OopClosureType>
160void InstanceRefKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
161 InstanceKlass::oop_oop_iterate<T>(obj, closure);
162
163 oop_oop_iterate_ref_processing<T>(obj, closure);
164}
165
166template <typename T, class OopClosureType>
167void InstanceRefKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closure) {
168 InstanceKlass::oop_oop_iterate_reverse<T>(obj, closure);
169
170 oop_oop_iterate_ref_processing<T>(obj, closure);
171}
172
173template <typename T, class OopClosureType>
174void InstanceRefKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) {
175 InstanceKlass::oop_oop_iterate_bounded<T>(obj, closure, mr);
176
177 oop_oop_iterate_ref_processing_bounded<T>(obj, closure, mr);
178}
179
180#ifdef ASSERT
181template <typename T>
182void InstanceRefKlass::trace_reference_gc(const char *s, oop obj) {
183 T* referent_addr = (T*) java_lang_ref_Reference::referent_addr_raw(obj);
184 T* discovered_addr = (T*) java_lang_ref_Reference::discovered_addr_raw(obj);
185
186 log_develop_trace(gc, ref)("InstanceRefKlass %s for obj " PTR_FORMAT, s, p2i(obj));
187 if (java_lang_ref_Reference::is_phantom(obj)) {
188 log_develop_trace(gc, ref)(" referent_addr/* " PTR_FORMAT " / " PTR_FORMAT,
189 p2i(referent_addr), p2i((oop)HeapAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(referent_addr)));
190 } else {
191 log_develop_trace(gc, ref)(" referent_addr/* " PTR_FORMAT " / " PTR_FORMAT,
192 p2i(referent_addr), p2i((oop)HeapAccess<ON_WEAK_OOP_REF | AS_NO_KEEPALIVE>::oop_load(referent_addr)));
193 }
194 log_develop_trace(gc, ref)(" discovered_addr/* " PTR_FORMAT " / " PTR_FORMAT,
195 p2i(discovered_addr), p2i((oop)HeapAccess<AS_NO_KEEPALIVE>::oop_load(discovered_addr)));
196}
197#endif
198
199#endif // SHARE_OOPS_INSTANCEREFKLASS_INLINE_HPP
200