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#include "precompiled.hpp"
25#include "gc/z/zBarrier.inline.hpp"
26#include "gc/z/zHeap.inline.hpp"
27#include "gc/z/zOop.inline.hpp"
28#include "gc/z/zOopClosures.inline.hpp"
29#include "memory/iterator.inline.hpp"
30#include "oops/oop.inline.hpp"
31#include "runtime/safepoint.hpp"
32#include "utilities/debug.hpp"
33
34bool ZBarrier::during_mark() {
35 return ZGlobalPhase == ZPhaseMark;
36}
37
38bool ZBarrier::during_relocate() {
39 return ZGlobalPhase == ZPhaseRelocate;
40}
41
42template <bool finalizable>
43bool ZBarrier::should_mark_through(uintptr_t addr) {
44 // Finalizable marked oops can still exists on the heap after marking
45 // has completed, in which case we just want to convert this into a
46 // good oop and not push it on the mark stack.
47 if (!during_mark()) {
48 assert(ZAddress::is_marked(addr), "Should be marked");
49 assert(ZAddress::is_finalizable(addr), "Should be finalizable");
50 return false;
51 }
52
53 // During marking, we mark through already marked oops to avoid having
54 // some large part of the object graph hidden behind a pushed, but not
55 // yet flushed, entry on a mutator mark stack. Always marking through
56 // allows the GC workers to proceed through the object graph even if a
57 // mutator touched an oop first, which in turn will reduce the risk of
58 // having to flush mark stacks multiple times to terminate marking.
59 //
60 // However, when doing finalizable marking we don't always want to mark
61 // through. First, marking through an already strongly marked oop would
62 // be wasteful, since we will then proceed to do finalizable marking on
63 // an object which is, or will be, marked strongly. Second, marking
64 // through an already finalizable marked oop would also be wasteful,
65 // since such oops can never end up on a mutator mark stack and can
66 // therefore not hide some part of the object graph from GC workers.
67 if (finalizable) {
68 return !ZAddress::is_marked(addr);
69 }
70
71 // Mark through
72 return true;
73}
74
75template <bool finalizable, bool publish>
76uintptr_t ZBarrier::mark(uintptr_t addr) {
77 uintptr_t good_addr;
78
79 if (ZAddress::is_marked(addr)) {
80 // Already marked, but try to mark though anyway
81 good_addr = ZAddress::good(addr);
82 } else if (ZAddress::is_remapped(addr)) {
83 // Already remapped, but also needs to be marked
84 good_addr = ZAddress::good(addr);
85 } else {
86 // Needs to be both remapped and marked
87 good_addr = remap(addr);
88 }
89
90 // Mark
91 if (should_mark_through<finalizable>(addr)) {
92 ZHeap::heap()->mark_object<finalizable, publish>(good_addr);
93 }
94
95 return good_addr;
96}
97
98uintptr_t ZBarrier::remap(uintptr_t addr) {
99 assert(!ZAddress::is_good(addr), "Should not be good");
100 assert(!ZAddress::is_weak_good(addr), "Should not be weak good");
101 return ZHeap::heap()->remap_object(addr);
102}
103
104uintptr_t ZBarrier::relocate(uintptr_t addr) {
105 assert(!ZAddress::is_good(addr), "Should not be good");
106 assert(!ZAddress::is_weak_good(addr), "Should not be weak good");
107 return ZHeap::heap()->relocate_object(addr);
108}
109
110uintptr_t ZBarrier::relocate_or_mark(uintptr_t addr) {
111 return during_relocate() ? relocate(addr) : mark<Strong, Publish>(addr);
112}
113
114uintptr_t ZBarrier::relocate_or_remap(uintptr_t addr) {
115 return during_relocate() ? relocate(addr) : remap(addr);
116}
117
118//
119// Load barrier
120//
121uintptr_t ZBarrier::load_barrier_on_oop_slow_path(uintptr_t addr) {
122 return relocate_or_mark(addr);
123}
124
125void ZBarrier::load_barrier_on_oop_fields(oop o) {
126 assert(ZAddress::is_good(ZOop::to_address(o)), "Should be good");
127 ZLoadBarrierOopClosure cl;
128 o->oop_iterate(&cl);
129}
130
131//
132// Weak load barrier
133//
134uintptr_t ZBarrier::weak_load_barrier_on_oop_slow_path(uintptr_t addr) {
135 return ZAddress::is_weak_good(addr) ? ZAddress::good(addr) : relocate_or_remap(addr);
136}
137
138uintptr_t ZBarrier::weak_load_barrier_on_weak_oop_slow_path(uintptr_t addr) {
139 const uintptr_t good_addr = weak_load_barrier_on_oop_slow_path(addr);
140 if (ZHeap::heap()->is_object_strongly_live(good_addr)) {
141 return good_addr;
142 }
143
144 // Not strongly live
145 return 0;
146}
147
148uintptr_t ZBarrier::weak_load_barrier_on_phantom_oop_slow_path(uintptr_t addr) {
149 const uintptr_t good_addr = weak_load_barrier_on_oop_slow_path(addr);
150 if (ZHeap::heap()->is_object_live(good_addr)) {
151 return good_addr;
152 }
153
154 // Not live
155 return 0;
156}
157
158//
159// Keep alive barrier
160//
161uintptr_t ZBarrier::keep_alive_barrier_on_weak_oop_slow_path(uintptr_t addr) {
162 const uintptr_t good_addr = weak_load_barrier_on_oop_slow_path(addr);
163 assert(ZHeap::heap()->is_object_strongly_live(good_addr), "Should be live");
164 return good_addr;
165}
166
167uintptr_t ZBarrier::keep_alive_barrier_on_phantom_oop_slow_path(uintptr_t addr) {
168 const uintptr_t good_addr = weak_load_barrier_on_oop_slow_path(addr);
169 assert(ZHeap::heap()->is_object_live(good_addr), "Should be live");
170 return good_addr;
171}
172
173//
174// Mark barrier
175//
176uintptr_t ZBarrier::mark_barrier_on_oop_slow_path(uintptr_t addr) {
177 return mark<Strong, Overflow>(addr);
178}
179
180uintptr_t ZBarrier::mark_barrier_on_finalizable_oop_slow_path(uintptr_t addr) {
181 const uintptr_t good_addr = mark<Finalizable, Overflow>(addr);
182 if (ZAddress::is_good(addr)) {
183 // If the oop was already strongly marked/good, then we do
184 // not want to downgrade it to finalizable marked/good.
185 return good_addr;
186 }
187
188 // Make the oop finalizable marked/good, instead of normal marked/good.
189 // This is needed because an object might first becomes finalizable
190 // marked by the GC, and then loaded by a mutator thread. In this case,
191 // the mutator thread must be able to tell that the object needs to be
192 // strongly marked. The finalizable bit in the oop exists to make sure
193 // that a load of a finalizable marked oop will fall into the barrier
194 // slow path so that we can mark the object as strongly reachable.
195 return ZAddress::finalizable_good(good_addr);
196}
197
198uintptr_t ZBarrier::mark_barrier_on_root_oop_slow_path(uintptr_t addr) {
199 assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint");
200 assert(during_mark(), "Invalid phase");
201
202 // Mark
203 return mark<Strong, Publish>(addr);
204}
205
206//
207// Relocate barrier
208//
209uintptr_t ZBarrier::relocate_barrier_on_root_oop_slow_path(uintptr_t addr) {
210 assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint");
211 assert(during_relocate(), "Invalid phase");
212
213 // Relocate
214 return relocate(addr);
215}
216
217//
218// Narrow oop variants, never used.
219//
220oop ZBarrier::load_barrier_on_oop_field(volatile narrowOop* p) {
221 ShouldNotReachHere();
222 return NULL;
223}
224
225oop ZBarrier::load_barrier_on_oop_field_preloaded(volatile narrowOop* p, oop o) {
226 ShouldNotReachHere();
227 return NULL;
228}
229
230void ZBarrier::load_barrier_on_oop_array(volatile narrowOop* p, size_t length) {
231 ShouldNotReachHere();
232}
233
234oop ZBarrier::load_barrier_on_weak_oop_field_preloaded(volatile narrowOop* p, oop o) {
235 ShouldNotReachHere();
236 return NULL;
237}
238
239oop ZBarrier::load_barrier_on_phantom_oop_field_preloaded(volatile narrowOop* p, oop o) {
240 ShouldNotReachHere();
241 return NULL;
242}
243
244oop ZBarrier::weak_load_barrier_on_oop_field_preloaded(volatile narrowOop* p, oop o) {
245 ShouldNotReachHere();
246 return NULL;
247}
248
249oop ZBarrier::weak_load_barrier_on_weak_oop_field_preloaded(volatile narrowOop* p, oop o) {
250 ShouldNotReachHere();
251 return NULL;
252}
253
254oop ZBarrier::weak_load_barrier_on_phantom_oop_field_preloaded(volatile narrowOop* p, oop o) {
255 ShouldNotReachHere();
256 return NULL;
257}
258