1/*
2 * Copyright (c) 2017, 2019, Red Hat, Inc. All rights reserved.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This code is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * version 2 for more details (a copy is included in the LICENSE file that
12 * accompanied this code).
13 *
14 * You should have received a copy of the GNU General Public License version
15 * 2 along with this work; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19 * or visit www.oracle.com if you need additional information or have any
20 * questions.
21 *
22 */
23
24#include "precompiled.hpp"
25
26#include "gc/shared/stringdedup/stringDedup.inline.hpp"
27#include "gc/shared/workgroup.hpp"
28#include "gc/shenandoah/shenandoahCollectionSet.inline.hpp"
29#include "gc/shenandoah/shenandoahHeap.inline.hpp"
30#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
31#include "gc/shenandoah/shenandoahStringDedup.hpp"
32#include "gc/shenandoah/shenandoahStrDedupQueue.hpp"
33#include "gc/shenandoah/shenandoahTimingTracker.hpp"
34#include "gc/shenandoah/shenandoahUtils.hpp"
35#include "runtime/thread.hpp"
36
37void ShenandoahStringDedup::initialize() {
38 assert(UseShenandoahGC, "String deduplication available with Shenandoah GC");
39 StringDedup::initialize_impl<ShenandoahStrDedupQueue, StringDedupStat>();
40}
41
42/* Enqueue candidates for deduplication.
43 * The method should only be called by GC worker threads during marking phases.
44 */
45void ShenandoahStringDedup::enqueue_candidate(oop java_string) {
46 assert(Thread::current()->is_Worker_thread(),
47 "Only from a GC worker thread");
48
49 if (java_string->age() <= StringDeduplicationAgeThreshold) {
50 const markOop mark = java_string->mark();
51
52 // Having/had displaced header, too risk to deal with them, skip
53 if (mark == markOopDesc::INFLATING() || mark->has_displaced_mark_helper()) {
54 return;
55 }
56
57 // Increase string age and enqueue it when it rearches age threshold
58 markOop new_mark = mark->incr_age();
59 if (mark == java_string->cas_set_mark(new_mark, mark)) {
60 if (mark->age() == StringDeduplicationAgeThreshold) {
61 StringDedupQueue::push(ShenandoahWorkerSession::worker_id(), java_string);
62 }
63 }
64 }
65}
66
67// Deduplicate a string, return true if it is deduplicated.
68void ShenandoahStringDedup::deduplicate(oop java_string) {
69 assert(is_enabled(), "String deduplication not enabled");
70 StringDedupStat dummy; // Statistics from this path is never used
71 StringDedupTable::deduplicate(java_string, &dummy);
72}
73
74void ShenandoahStringDedup::parallel_oops_do(BoolObjectClosure* is_alive, OopClosure* cl, uint worker_id) {
75 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
76 assert(is_enabled(), "String deduplication not enabled");
77
78 ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
79
80 StringDedupUnlinkOrOopsDoClosure sd_cl(is_alive, cl);
81
82 {
83 ShenandoahWorkerTimingsTracker x(worker_times, ShenandoahPhaseTimings::StringDedupQueueRoots, worker_id);
84 StringDedupQueue::unlink_or_oops_do(&sd_cl);
85 }
86 {
87 ShenandoahWorkerTimingsTracker x(worker_times, ShenandoahPhaseTimings::StringDedupTableRoots, worker_id);
88 StringDedupTable::unlink_or_oops_do(&sd_cl, worker_id);
89 }
90}
91
92void ShenandoahStringDedup::oops_do_slow(OopClosure* cl) {
93 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
94 assert(is_enabled(), "String deduplication not enabled");
95 AlwaysTrueClosure always_true;
96 StringDedupUnlinkOrOopsDoClosure sd_cl(&always_true, cl);
97 StringDedupQueue::unlink_or_oops_do(&sd_cl);
98 StringDedupTable::unlink_or_oops_do(&sd_cl, 0);
99}
100
101class ShenandoahIsMarkedNextClosure : public BoolObjectClosure {
102private:
103 ShenandoahMarkingContext* const _mark_context;
104
105public:
106 ShenandoahIsMarkedNextClosure() : _mark_context(ShenandoahHeap::heap()->marking_context()) { }
107
108 bool do_object_b(oop obj) {
109 return _mark_context->is_marked(obj);
110 }
111};
112
113//
114// Task for parallel unlink_or_oops_do() operation on the deduplication queue
115// and table.
116//
117class ShenandoahStringDedupUnlinkOrOopsDoTask : public AbstractGangTask {
118private:
119 StringDedupUnlinkOrOopsDoClosure _cl;
120
121public:
122 ShenandoahStringDedupUnlinkOrOopsDoTask(BoolObjectClosure* is_alive,
123 OopClosure* keep_alive,
124 bool allow_resize_and_rehash) :
125 AbstractGangTask("StringDedupUnlinkOrOopsDoTask"),
126 _cl(is_alive, keep_alive) {
127 StringDedup::gc_prologue(allow_resize_and_rehash);
128 }
129
130 ~ShenandoahStringDedupUnlinkOrOopsDoTask() {
131 StringDedup::gc_epilogue();
132 }
133
134 virtual void work(uint worker_id) {
135 StringDedupQueue::unlink_or_oops_do(&_cl);
136 StringDedupTable::unlink_or_oops_do(&_cl, worker_id);
137 }
138};
139
140void ShenandoahStringDedup::unlink_or_oops_do(BoolObjectClosure* is_alive,
141 OopClosure* keep_alive,
142 bool allow_resize_and_rehash) {
143 assert(is_enabled(), "String deduplication not enabled");
144
145 ShenandoahStringDedupUnlinkOrOopsDoTask task(is_alive, keep_alive, allow_resize_and_rehash);
146 ShenandoahHeap* heap = ShenandoahHeap::heap();
147 heap->workers()->run_task(&task);
148}
149