1 /*
  2  * Copyright (c) 2021, Amazon.com, Inc. or its affiliates.  All rights reserved.
  3  *
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  *
 24  */
 25 
 26 
 27 #include "precompiled.hpp"
 28 
 29 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
 30 #include "gc/shenandoah/shenandoahOopClosures.inline.hpp"
 31 #include "gc/shenandoah/shenandoahReferenceProcessor.hpp"
 32 #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp"
 33 
 34 ShenandoahDirectCardMarkRememberedSet::ShenandoahDirectCardMarkRememberedSet(ShenandoahCardTable* card_table, size_t total_card_count) {
 35   _heap = ShenandoahHeap::heap();
 36   _card_table = card_table;
 37   _total_card_count = total_card_count;
 38   _cluster_count = total_card_count / ShenandoahCardCluster<ShenandoahDirectCardMarkRememberedSet>::CardsPerCluster;
 39   _card_shift = CardTable::card_shift;
 40 
 41   _byte_map = _card_table->byte_for_index(0);
 42 
 43   _whole_heap_base = _card_table->addr_for(_byte_map);
 44   _whole_heap_end = _whole_heap_base + total_card_count * CardTable::card_size;
 45 
 46   _byte_map_base = _byte_map - (uintptr_t(_whole_heap_base) >> _card_shift);
 47 
 48   _overreach_map = (uint8_t *) malloc(total_card_count);
 49   _overreach_map_base = (_overreach_map -
 50                          (uintptr_t(_whole_heap_base) >> _card_shift));
 51 
 52   assert(total_card_count % ShenandoahCardCluster<ShenandoahDirectCardMarkRememberedSet>::CardsPerCluster == 0, "Invalid card count.");
 53   assert(total_card_count > 0, "Card count cannot be zero.");
 54   // assert(_overreach_cards != NULL);
 55 }
 56 
 57 ShenandoahDirectCardMarkRememberedSet::~ShenandoahDirectCardMarkRememberedSet() {
 58   free(_overreach_map);
 59 }
 60 
 61 void ShenandoahDirectCardMarkRememberedSet::initialize_overreach(size_t first_cluster, size_t count) {
 62 
 63   // We can make this run faster in the future by explicitly
 64   // unrolling the loop and doing wide writes if the compiler
 65   // doesn't do this for us.
 66   size_t first_card_index = first_cluster * ShenandoahCardCluster<ShenandoahDirectCardMarkRememberedSet>::CardsPerCluster;
 67   uint8_t* omp = &_overreach_map[first_card_index];
 68   uint8_t* endp = omp + count * ShenandoahCardCluster<ShenandoahDirectCardMarkRememberedSet>::CardsPerCluster;
 69   while (omp < endp)
 70     *omp++ = CardTable::clean_card_val();
 71 }
 72 
 73 void ShenandoahDirectCardMarkRememberedSet::merge_overreach(size_t first_cluster, size_t count) {
 74 
 75   // We can make this run faster in the future by explicitly unrolling the loop and doing wide writes if the compiler
 76   // doesn't do this for us.
 77   size_t first_card_index = first_cluster * ShenandoahCardCluster<ShenandoahDirectCardMarkRememberedSet>::CardsPerCluster;
 78   uint8_t* bmp = &_byte_map[first_card_index];
 79   uint8_t* endp = bmp + count * ShenandoahCardCluster<ShenandoahDirectCardMarkRememberedSet>::CardsPerCluster;
 80   uint8_t* omp = &_overreach_map[first_card_index];
 81 
 82   // dirty_card is 0, clean card is 0xff; if either *bmp or *omp is dirty, we need to mark it as dirty
 83   while (bmp < endp)
 84     *bmp++ &= *omp++;
 85 }
 86 
 87 ShenandoahScanRememberedTask::ShenandoahScanRememberedTask(ShenandoahObjToScanQueueSet* queue_set,
 88                                                            ShenandoahObjToScanQueueSet* old_queue_set,
 89                                                            ShenandoahReferenceProcessor* rp,
 90                                                            ShenandoahRegionIterator* regions) :
 91   AbstractGangTask("Scan Remembered Set"),
 92   _queue_set(queue_set), _old_queue_set(old_queue_set), _rp(rp), _regions(regions) {}
 93 
 94 void ShenandoahScanRememberedTask::work(uint worker_id) {
 95   // This sets up a thread local reference to the worker_id which is necessary
 96   // the weak reference processor.
 97   ShenandoahParallelWorkerSession worker_session(worker_id);
 98   ShenandoahWorkerTimingsTracker x(ShenandoahPhaseTimings::init_scan_rset, ShenandoahPhaseTimings::ScanClusters, worker_id);
 99 
100   ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id);
101   ShenandoahObjToScanQueue* old = _old_queue_set == NULL ? NULL : _old_queue_set->queue(worker_id);
102   ShenandoahMarkRefsClosure<YOUNG> cl(q, _rp, old);
103   RememberedScanner* scanner = ShenandoahHeap::heap()->card_scan();
104 
105   // set up thread local closure for shen ref processor
106   _rp->set_mark_closure(worker_id, &cl);
107   ShenandoahHeapRegion* region = _regions->next();
108   while (region != NULL) {
109     log_debug(gc)("ShenandoahScanRememberedTask::work(%u), looking at region " SIZE_FORMAT, worker_id, region->index());
110     if (region->affiliation() == OLD_GENERATION) {
111       scanner->process_region(region, &cl);
112     }
113     region = _regions->next();
114   }
115 }