1 /* 2 * Copyright (c) 2017, 2018, 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.hpp" 27 #include "gc/shared/stringdedup/stringDedup.inline.hpp" 28 #include "gc/shared/workgroup.hpp" 29 #include "gc/shenandoah/shenandoahCollectionSet.hpp" 30 #include "gc/shenandoah/shenandoahCollectionSet.inline.hpp" 31 #include "gc/shenandoah/shenandoahHeap.hpp" 32 #include "gc/shenandoah/shenandoahHeap.inline.hpp" 33 #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" 34 #include "gc/shenandoah/shenandoahStringDedup.hpp" 35 #include "gc/shenandoah/shenandoahStrDedupQueue.hpp" 36 #include "gc/shenandoah/shenandoahTimingTracker.hpp" 37 #include "gc/shenandoah/shenandoahUtils.hpp" 38 #include "runtime/thread.hpp" 39 40 void ShenandoahStringDedup::initialize() { 41 assert(UseShenandoahGC, "String deduplication available with Shenandoah GC"); 42 StringDedup::initialize_impl<ShenandoahStrDedupQueue, StringDedupStat>(); 43 } 44 45 /* Enqueue candidates for deduplication. 46 * The method should only be called by GC worker threads during marking phases. 47 */ 48 void ShenandoahStringDedup::enqueue_candidate(oop java_string) { 49 assert(Thread::current()->is_Worker_thread(), 50 "Only from a GC worker thread"); 51 52 if (java_string->age() <= StringDeduplicationAgeThreshold) { 53 const markOop mark = java_string->mark(); 54 55 // Having/had displaced header, too risk to deal with them, skip 56 if (mark == markOopDesc::INFLATING() || mark->has_displaced_mark_helper()) { 57 return; 58 } 59 60 // Increase string age and enqueue it when it rearches age threshold 61 markOop new_mark = mark->incr_age(); 62 if (mark == java_string->cas_set_mark(new_mark, mark)) { 63 if (mark->age() == StringDeduplicationAgeThreshold) { 64 StringDedupQueue::push(ShenandoahWorkerSession::worker_id(), java_string); 65 } 66 } 67 } 68 } 69 70 // Deduplicate a string, return true if it is deduplicated. 71 void ShenandoahStringDedup::deduplicate(oop java_string) { 72 assert(is_enabled(), "String deduplication not enabled"); 73 StringDedupStat dummy; // Statistics from this path is never used 74 StringDedupTable::deduplicate(java_string, &dummy); 75 } 76 77 void ShenandoahStringDedup::parallel_oops_do(OopClosure* cl, uint worker_id) { 78 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); 79 assert(is_enabled(), "String deduplication not enabled"); 80 81 ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times(); 82 83 StringDedupUnlinkOrOopsDoClosure sd_cl(NULL, cl); 84 85 { 86 ShenandoahWorkerTimingsTracker x(worker_times, ShenandoahPhaseTimings::StringDedupQueueRoots, worker_id); 87 StringDedupQueue::unlink_or_oops_do(&sd_cl); 88 } 89 { 90 ShenandoahWorkerTimingsTracker x(worker_times, ShenandoahPhaseTimings::StringDedupTableRoots, worker_id); 91 StringDedupTable::unlink_or_oops_do(&sd_cl, worker_id); 92 } 93 } 94 95 void ShenandoahStringDedup::oops_do_slow(OopClosure* cl) { 96 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); 97 assert(is_enabled(), "String deduplication not enabled"); 98 ShenandoahAlwaysTrueClosure always_true; 99 StringDedupUnlinkOrOopsDoClosure sd_cl(&always_true, cl); 100 StringDedupQueue::unlink_or_oops_do(&sd_cl); 101 StringDedupTable::unlink_or_oops_do(&sd_cl, 0); 102 } 103 104 class ShenandoahIsMarkedNextClosure : public BoolObjectClosure { 105 private: 106 ShenandoahMarkingContext* const _mark_context; 107 108 public: 109 ShenandoahIsMarkedNextClosure() : _mark_context(ShenandoahHeap::heap()->marking_context()) { } 110 111 bool do_object_b(oop obj) { 112 return _mark_context->is_marked(obj); 113 } 114 }; 115 116 void ShenandoahStringDedup::parallel_cleanup() { 117 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); 118 log_debug(gc, stringdedup)("String dedup cleanup"); 119 ShenandoahIsMarkedNextClosure cl; 120 121 unlink_or_oops_do(&cl, NULL, true); 122 } 123 124 // 125 // Task for parallel unlink_or_oops_do() operation on the deduplication queue 126 // and table. 127 // 128 class ShenandoahStringDedupUnlinkOrOopsDoTask : public AbstractGangTask { 129 private: 130 StringDedupUnlinkOrOopsDoClosure _cl; 131 132 public: 133 ShenandoahStringDedupUnlinkOrOopsDoTask(BoolObjectClosure* is_alive, 134 OopClosure* keep_alive, 135 bool allow_resize_and_rehash) : 136 AbstractGangTask("StringDedupUnlinkOrOopsDoTask"), 137 _cl(is_alive, keep_alive) { 138 StringDedup::gc_prologue(allow_resize_and_rehash); 139 } 140 141 ~ShenandoahStringDedupUnlinkOrOopsDoTask() { 142 StringDedup::gc_epilogue(); 143 } 144 145 virtual void work(uint worker_id) { 146 StringDedupQueue::unlink_or_oops_do(&_cl); 147 StringDedupTable::unlink_or_oops_do(&_cl, worker_id); 148 } 149 }; 150 151 void ShenandoahStringDedup::unlink_or_oops_do(BoolObjectClosure* is_alive, 152 OopClosure* keep_alive, 153 bool allow_resize_and_rehash) { 154 assert(is_enabled(), "String deduplication not enabled"); 155 156 ShenandoahStringDedupUnlinkOrOopsDoTask task(is_alive, keep_alive, allow_resize_and_rehash); 157 ShenandoahHeap* heap = ShenandoahHeap::heap(); 158 heap->workers()->run_task(&task); 159 }