1 /*
   2  * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates.
   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 "classfile/javaClasses.inline.hpp"
  27 #include "gc/g1/g1StringDedup.hpp"
  28 #include "gc/g1/g1StringDedupQueue.hpp"
  29 #include "gc/g1/g1StringDedupTable.hpp"
  30 #include "gc/g1/g1StringDedupThread.hpp"
  31 #include "gc/shared/workgroup.hpp"
  32 #include "gc/shenandoah/brooksPointer.hpp"
  33 #include "gc/shenandoah/shenandoahCollectionSet.hpp"
  34 #include "gc/shenandoah/shenandoahCollectionSet.inline.hpp"
  35 #include "gc/shenandoah/shenandoahHeap.hpp"
  36 #include "gc/shenandoah/shenandoahStringDedup.hpp"
  37 #include "logging/log.hpp"
  38 #include "runtime/safepoint.hpp"
  39 
  40 
  41 // This closure is only used during full gc, after references are adjusted,
  42 // and before heap compaction. No oop verification can be performed.
  43 class ShenandoahIsAliveCompleteClosure: public BoolObjectClosure {
  44 private:
  45   ShenandoahHeap* _heap;
  46 public:
  47   ShenandoahIsAliveCompleteClosure() : _heap(ShenandoahHeap::heap()) {
  48   }
  49 
  50   bool do_object_b(oop obj) {
  51     assert(!oopDesc::is_null(obj), "null");
  52     return _heap->is_marked(obj);
  53   }
  54 };
  55 
  56 // Same as above
  57 class ShenandoahUpdateLiveRefsClosure: public OopClosure {
  58 private:
  59   ShenandoahHeap* _heap;
  60 
  61   template <class T>
  62   inline void do_oop_work(T* p) {
  63     T o = oopDesc::load_heap_oop(p);
  64     if (! oopDesc::is_null(o)) {
  65       oop obj = oopDesc::decode_heap_oop_not_null(o);
  66       assert(_heap->is_in(obj), "Must be in the heap");
  67       HeapWord* ptr = BrooksPointer::get_raw(obj);
  68       oop forw = oop(ptr);
  69 
  70       assert(_heap->is_in(forw), "Must be in the heap");
  71       assert(!oopDesc::is_null(forw), "Can not be null");
  72       if (!oopDesc::unsafe_equals(forw, obj)) {
  73         oopDesc::encode_store_heap_oop(p, forw);
  74       }
  75     } else {
  76       assert(false, "NULL oop");
  77     }
  78   }
  79 
  80 public:
  81   ShenandoahUpdateLiveRefsClosure() : _heap(ShenandoahHeap::heap()) {
  82   }
  83 
  84   inline void do_oop(oop* p)        { do_oop_work(p); }
  85   inline void do_oop(narrowOop* p)  { do_oop_work(p); }
  86 };
  87 
  88 
  89 // Perform String Dedup update and/or cleanup task
  90 class ShenandoahStringDedupTableUpdateOrUnlinkTask : public AbstractGangTask {
  91 private:
  92   G1StringDedupUnlinkOrOopsDoClosure  _dedup_closure;
  93 public:
  94   ShenandoahStringDedupTableUpdateOrUnlinkTask(BoolObjectClosure* is_alive_closure, OopClosure* keep_alive_closure)
  95   : AbstractGangTask("Shenandoah Dedup unlink task"),
  96     _dedup_closure(is_alive_closure, keep_alive_closure, true) {
  97   }
  98 
  99   void work(uint worker_id) {
 100     G1StringDedup::parallel_unlink(&_dedup_closure, worker_id);
 101   }
 102 };
 103 
 104 
 105 void ShenandoahStringDedup::initialize() {
 106   assert(UseShenandoahGC, "String deduplication available with ShenandoahGC");
 107   if (UseStringDeduplication) {
 108     _enabled = true;
 109     G1StringDedupQueue::create(ShenandoahHeap::heap()->max_workers());
 110     G1StringDedupTable::create();
 111     G1StringDedupThread::create("Shenandoah StrDedup");
 112   }
 113 }
 114 
 115 
 116 void ShenandoahStringDedup::try_dedup(oop java_string) {
 117   if (is_candidate(java_string)) {
 118     G1StringDedup::deduplicate(java_string);
 119   }
 120 }
 121 
 122 void ShenandoahStringDedup::enqueue_from_safepoint(oop java_string, uint worker_id) {
 123   assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
 124   assert(Thread::current()->is_Worker_thread(), "Must be a worker thread");
 125   assert(worker_id < ShenandoahHeap::heap()->max_workers(), "Sanity");
 126 
 127   G1StringDedupQueue::push(worker_id, java_string);
 128 }
 129 
 130 
 131 void ShenandoahStringDedup::parallel_full_gc_update_or_unlink() {
 132   assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
 133   assert(ShenandoahHeap::heap()->is_full_gc_in_progress(), "Must be during full gc");
 134 
 135   ShenandoahUpdateLiveRefsClosure  update_refs_closure;
 136   ShenandoahIsAliveCompleteClosure is_alive_closure;
 137   ShenandoahStringDedupTableUpdateOrUnlinkTask task(&is_alive_closure, &update_refs_closure);
 138   ShenandoahHeap::heap()->workers()->run_task(&task);
 139 }
 140 
 141 
 142 void ShenandoahStringDedup::parallel_update_refs() {
 143   assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
 144   ShenandoahUpdateRefsClosure update_refs_closure;
 145   ShenandoahAlwaysTrueClosure is_alive_closure;
 146   ShenandoahStringDedupTableUpdateOrUnlinkTask task(&is_alive_closure, &update_refs_closure);
 147   ShenandoahHeap::heap()->workers()->run_task(&task);
 148 }
 149 
 150 
 151 void ShenandoahStringDedup::parallel_cleanup() {
 152   assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
 153   ShenandoahForwardedIsAliveClosure is_alive_closure;
 154   ShenandoahStringDedupTableUpdateOrUnlinkTask task(&is_alive_closure, NULL);
 155   ShenandoahHeap::heap()->workers()->run_task(&task);
 156 }
 157 
 158 
 159 // Only used during partial GC after evacuation.
 160 // We don't have accurate bitmap during partial GC to determine liveness of
 161 // an object. So after evacuation, if the object is in collection set but not
 162 // evacuated, it is dead.
 163 class ShenandoahPartialIsAliveClosure: public BoolObjectClosure {
 164 private:
 165   ShenandoahHeap* _heap;
 166 public:
 167   ShenandoahPartialIsAliveClosure() : _heap(ShenandoahHeap::heap()) {
 168   }
 169 
 170   bool do_object_b(oop obj);
 171 };
 172 
 173 bool ShenandoahPartialIsAliveClosure::do_object_b(oop obj) {
 174   if (_heap->in_collection_set(obj)) {
 175     oop forw = ShenandoahBarrierSet::resolve_oop_static_not_null(obj);
 176     return !oopDesc::unsafe_equals(forw, obj);
 177   }
 178 
 179   return true;
 180 }
 181 
 182 
 183 void ShenandoahStringDedup::parallel_partial_update_or_unlink() {
 184   assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
 185   ShenandoahUpdateLiveRefsClosure update_refs_closure;
 186   ShenandoahPartialIsAliveClosure is_alive_closure;
 187   ShenandoahStringDedupTableUpdateOrUnlinkTask task(&is_alive_closure, &update_refs_closure);
 188   ShenandoahHeap::heap()->workers()->run_task(&task);
 189 }