| File: | jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp |
| Warning: | line 144, column 19 The result of the left shift is undefined because the right operand is negative |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright (c) 2021, Red Hat, Inc. 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 | ||||
| 25 | ||||
| 26 | #include "precompiled.hpp" | |||
| 27 | ||||
| 28 | #include "gc/shenandoah/shenandoahBarrierSet.hpp" | |||
| 29 | #include "gc/shenandoah/shenandoahClosures.inline.hpp" | |||
| 30 | #include "gc/shenandoah/shenandoahMark.inline.hpp" | |||
| 31 | #include "gc/shenandoah/shenandoahOopClosures.inline.hpp" | |||
| 32 | #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" | |||
| 33 | #include "gc/shenandoah/shenandoahTaskqueue.inline.hpp" | |||
| 34 | #include "gc/shenandoah/shenandoahUtils.hpp" | |||
| 35 | #include "gc/shenandoah/shenandoahVerifier.hpp" | |||
| 36 | ||||
| 37 | ShenandoahMarkRefsSuperClosure::ShenandoahMarkRefsSuperClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp) : | |||
| 38 | MetadataVisitingOopIterateClosure(rp), | |||
| 39 | _queue(q), | |||
| 40 | _mark_context(ShenandoahHeap::heap()->marking_context()), | |||
| 41 | _weak(false) | |||
| 42 | { } | |||
| 43 | ||||
| 44 | ShenandoahMark::ShenandoahMark() : | |||
| 45 | _task_queues(ShenandoahHeap::heap()->marking_context()->task_queues()) { | |||
| 46 | } | |||
| 47 | ||||
| 48 | void ShenandoahMark::clear() { | |||
| 49 | // Clean up marking stacks. | |||
| 50 | ShenandoahObjToScanQueueSet* queues = ShenandoahHeap::heap()->marking_context()->task_queues(); | |||
| 51 | queues->clear(); | |||
| 52 | ||||
| 53 | // Cancel SATB buffers. | |||
| 54 | ShenandoahBarrierSet::satb_mark_queue_set().abandon_partial_marking(); | |||
| 55 | } | |||
| 56 | ||||
| 57 | template <bool CANCELLABLE, StringDedupMode STRING_DEDUP> | |||
| 58 | void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahReferenceProcessor *rp, StringDedup::Requests* const req) { | |||
| 59 | ShenandoahObjToScanQueue* q = get_queue(w); | |||
| 60 | ||||
| 61 | ShenandoahHeap* const heap = ShenandoahHeap::heap(); | |||
| 62 | ShenandoahLiveData* ld = heap->get_liveness_cache(w); | |||
| 63 | ||||
| 64 | // TODO: We can clean up this if we figure out how to do templated oop closures that | |||
| 65 | // play nice with specialized_oop_iterators. | |||
| 66 | if (heap->unload_classes()) { | |||
| 67 | if (heap->has_forwarded_objects()) { | |||
| 68 | using Closure = ShenandoahMarkUpdateRefsMetadataClosure; | |||
| 69 | Closure cl(q, rp); | |||
| 70 | mark_loop_work<Closure, CANCELLABLE, STRING_DEDUP>(&cl, ld, w, t, req); | |||
| 71 | } else { | |||
| 72 | using Closure = ShenandoahMarkRefsMetadataClosure; | |||
| 73 | Closure cl(q, rp); | |||
| 74 | mark_loop_work<Closure, CANCELLABLE, STRING_DEDUP>(&cl, ld, w, t, req); | |||
| 75 | } | |||
| 76 | } else { | |||
| 77 | if (heap->has_forwarded_objects()) { | |||
| 78 | using Closure = ShenandoahMarkUpdateRefsClosure; | |||
| 79 | Closure cl(q, rp); | |||
| 80 | mark_loop_work<Closure, CANCELLABLE, STRING_DEDUP>(&cl, ld, w, t, req); | |||
| 81 | } else { | |||
| 82 | using Closure = ShenandoahMarkRefsClosure; | |||
| 83 | Closure cl(q, rp); | |||
| 84 | mark_loop_work<Closure, CANCELLABLE, STRING_DEDUP>(&cl, ld, w, t, req); | |||
| 85 | } | |||
| 86 | } | |||
| 87 | ||||
| 88 | heap->flush_liveness_cache(w); | |||
| 89 | } | |||
| 90 | ||||
| 91 | void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahReferenceProcessor *rp, | |||
| 92 | bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req) { | |||
| 93 | if (cancellable) { | |||
| 94 | switch(dedup_mode) { | |||
| 95 | case NO_DEDUP: | |||
| 96 | mark_loop_prework<true, NO_DEDUP>(worker_id, terminator, rp, req); | |||
| 97 | break; | |||
| 98 | case ENQUEUE_DEDUP: | |||
| 99 | mark_loop_prework<true, ENQUEUE_DEDUP>(worker_id, terminator, rp, req); | |||
| 100 | break; | |||
| 101 | case ALWAYS_DEDUP: | |||
| 102 | mark_loop_prework<true, ALWAYS_DEDUP>(worker_id, terminator, rp, req); | |||
| 103 | break; | |||
| 104 | } | |||
| 105 | } else { | |||
| 106 | switch(dedup_mode) { | |||
| 107 | case NO_DEDUP: | |||
| 108 | mark_loop_prework<false, NO_DEDUP>(worker_id, terminator, rp, req); | |||
| 109 | break; | |||
| 110 | case ENQUEUE_DEDUP: | |||
| 111 | mark_loop_prework<false, ENQUEUE_DEDUP>(worker_id, terminator, rp, req); | |||
| 112 | break; | |||
| 113 | case ALWAYS_DEDUP: | |||
| 114 | mark_loop_prework<false, ALWAYS_DEDUP>(worker_id, terminator, rp, req); | |||
| 115 | break; | |||
| 116 | } | |||
| 117 | } | |||
| 118 | } | |||
| 119 | ||||
| 120 | template <class T, bool CANCELLABLE, StringDedupMode STRING_DEDUP> | |||
| 121 | void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *terminator, StringDedup::Requests* const req) { | |||
| 122 | uintx stride = ShenandoahMarkLoopStride; | |||
| 123 | ||||
| 124 | ShenandoahHeap* heap = ShenandoahHeap::heap(); | |||
| 125 | ShenandoahObjToScanQueueSet* queues = task_queues(); | |||
| 126 | ShenandoahObjToScanQueue* q; | |||
| 127 | ShenandoahMarkTask t; | |||
| 128 | ||||
| 129 | heap->ref_processor()->set_mark_closure(worker_id, cl); | |||
| 130 | ||||
| 131 | /* | |||
| 132 | * Process outstanding queues, if any. | |||
| 133 | * | |||
| 134 | * There can be more queues than workers. To deal with the imbalance, we claim | |||
| 135 | * extra queues first. Since marking can push new tasks into the queue associated | |||
| 136 | * with this worker id, we come back to process this queue in the normal loop. | |||
| 137 | */ | |||
| 138 | assert(queues->get_reserved() == heap->workers()->active_workers(),do { if (!(queues->get_reserved() == heap->workers()-> active_workers())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp" , 139, "assert(" "queues->get_reserved() == heap->workers()->active_workers()" ") failed", "Need to reserve proper number of queues: reserved: %u, active: %u" , queues->get_reserved(), heap->workers()->active_workers ()); ::breakpoint(); } } while (0) | |||
| ||||
| 139 | "Need to reserve proper number of queues: reserved: %u, active: %u", queues->get_reserved(), heap->workers()->active_workers())do { if (!(queues->get_reserved() == heap->workers()-> active_workers())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp" , 139, "assert(" "queues->get_reserved() == heap->workers()->active_workers()" ") failed", "Need to reserve proper number of queues: reserved: %u, active: %u" , queues->get_reserved(), heap->workers()->active_workers ()); ::breakpoint(); } } while (0); | |||
| 140 | ||||
| 141 | q = queues->claim_next(); | |||
| 142 | while (q != NULL__null) { | |||
| 143 | if (CANCELLABLE && heap->check_cancelled_gc_and_yield()) { | |||
| 144 | return; | |||
| 145 | } | |||
| 146 | ||||
| 147 | for (uint i = 0; i < stride; i++) { | |||
| 148 | if (q->pop(t)) { | |||
| 149 | do_task<T, STRING_DEDUP>(q, cl, live_data, req, &t); | |||
| 150 | } else { | |||
| 151 | assert(q->is_empty(), "Must be empty")do { if (!(q->is_empty())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp" , 151, "assert(" "q->is_empty()" ") failed", "Must be empty" ); ::breakpoint(); } } while (0); | |||
| 152 | q = queues->claim_next(); | |||
| 153 | break; | |||
| 154 | } | |||
| 155 | } | |||
| 156 | } | |||
| 157 | q = get_queue(worker_id); | |||
| 158 | ||||
| 159 | ShenandoahSATBBufferClosure drain_satb(q); | |||
| 160 | SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set(); | |||
| 161 | ||||
| 162 | /* | |||
| 163 | * Normal marking loop: | |||
| 164 | */ | |||
| 165 | while (true) { | |||
| 166 | if (CANCELLABLE && heap->check_cancelled_gc_and_yield()) { | |||
| 167 | return; | |||
| 168 | } | |||
| 169 | ||||
| 170 | while (satb_mq_set.completed_buffers_num() > 0) { | |||
| 171 | satb_mq_set.apply_closure_to_completed_buffer(&drain_satb); | |||
| 172 | } | |||
| 173 | ||||
| 174 | uint work = 0; | |||
| 175 | for (uint i = 0; i < stride; i++) { | |||
| 176 | if (q->pop(t) || | |||
| 177 | queues->steal(worker_id, t)) { | |||
| 178 | do_task<T, STRING_DEDUP>(q, cl, live_data, req, &t); | |||
| 179 | work++; | |||
| 180 | } else { | |||
| 181 | break; | |||
| 182 | } | |||
| 183 | } | |||
| 184 | ||||
| 185 | if (work == 0) { | |||
| 186 | // No work encountered in current stride, try to terminate. | |||
| 187 | // Need to leave the STS here otherwise it might block safepoints. | |||
| 188 | ShenandoahSuspendibleThreadSetLeaver stsl(CANCELLABLE && ShenandoahSuspendibleWorkers); | |||
| 189 | ShenandoahTerminatorTerminator tt(heap); | |||
| 190 | if (terminator->offer_termination(&tt)) return; | |||
| 191 | } | |||
| 192 | } | |||
| 193 | } |
| 1 | /* | |||
| 2 | * Copyright (c) 2015, 2021, Red Hat, Inc. 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 | ||||
| 25 | #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHMARK_INLINE_HPP | |||
| 26 | #define SHARE_GC_SHENANDOAH_SHENANDOAHMARK_INLINE_HPP | |||
| 27 | ||||
| 28 | #include "gc/shenandoah/shenandoahMark.hpp" | |||
| 29 | ||||
| 30 | #include "gc/shenandoah/shenandoahAsserts.hpp" | |||
| 31 | #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" | |||
| 32 | #include "gc/shenandoah/shenandoahHeap.inline.hpp" | |||
| 33 | #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" | |||
| 34 | #include "gc/shenandoah/shenandoahStringDedup.inline.hpp" | |||
| 35 | #include "gc/shenandoah/shenandoahTaskqueue.inline.hpp" | |||
| 36 | #include "gc/shenandoah/shenandoahUtils.hpp" | |||
| 37 | #include "memory/iterator.inline.hpp" | |||
| 38 | #include "oops/compressedOops.inline.hpp" | |||
| 39 | #include "oops/oop.inline.hpp" | |||
| 40 | #include "runtime/prefetch.inline.hpp" | |||
| 41 | #include "utilities/powerOfTwo.hpp" | |||
| 42 | ||||
| 43 | template <StringDedupMode STRING_DEDUP> | |||
| 44 | void ShenandoahMark::dedup_string(oop obj, StringDedup::Requests* const req) { | |||
| 45 | if (STRING_DEDUP == ENQUEUE_DEDUP) { | |||
| 46 | if (ShenandoahStringDedup::is_candidate(obj)) { | |||
| 47 | req->add(obj); | |||
| 48 | } | |||
| 49 | } else if (STRING_DEDUP == ALWAYS_DEDUP) { | |||
| 50 | if (ShenandoahStringDedup::is_string_candidate(obj) && | |||
| 51 | !ShenandoahStringDedup::dedup_requested(obj)) { | |||
| 52 | req->add(obj); | |||
| 53 | } | |||
| 54 | } | |||
| 55 | } | |||
| 56 | ||||
| 57 | template <class T, StringDedupMode STRING_DEDUP> | |||
| 58 | void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, StringDedup::Requests* const req, ShenandoahMarkTask* task) { | |||
| 59 | oop obj = task->obj(); | |||
| 60 | ||||
| 61 | shenandoah_assert_not_forwarded(NULL, obj)ShenandoahAsserts::assert_not_forwarded(__null, obj, "/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 61); | |||
| 62 | shenandoah_assert_marked(NULL, obj)ShenandoahAsserts::assert_marked(__null, obj, "/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 62); | |||
| 63 | shenandoah_assert_not_in_cset_except(NULL, obj, ShenandoahHeap::heap()->cancelled_gc())if (!(ShenandoahHeap::heap()->cancelled_gc())) ShenandoahAsserts ::assert_not_in_cset(__null, obj, "/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 63); | |||
| 64 | ||||
| 65 | // Are we in weak subgraph scan? | |||
| 66 | bool weak = task->is_weak(); | |||
| 67 | cl->set_weak(weak); | |||
| 68 | ||||
| 69 | if (task->is_not_chunked()) { | |||
| 70 | if (obj->is_instance()) { | |||
| 71 | // Case 1: Normal oop, process as usual. | |||
| 72 | obj->oop_iterate(cl); | |||
| 73 | dedup_string<STRING_DEDUP>(obj, req); | |||
| 74 | } else if (obj->is_objArray()) { | |||
| 75 | // Case 2: Object array instance and no chunk is set. Must be the first | |||
| 76 | // time we visit it, start the chunked processing. | |||
| 77 | do_chunked_array_start<T>(q, cl, obj, weak); | |||
| 78 | } else { | |||
| 79 | // Case 3: Primitive array. Do nothing, no oops there. We use the same | |||
| 80 | // performance tweak TypeArrayKlass::oop_oop_iterate_impl is using: | |||
| 81 | // We skip iterating over the klass pointer since we know that | |||
| 82 | // Universe::TypeArrayKlass never moves. | |||
| 83 | assert (obj->is_typeArray(), "should be type array")do { if (!(obj->is_typeArray())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 83, "assert(" "obj->is_typeArray()" ") failed", "should be type array" ); ::breakpoint(); } } while (0); | |||
| 84 | } | |||
| 85 | // Count liveness the last: push the outstanding work to the queues first | |||
| 86 | // Avoid double-counting objects that are visited twice due to upgrade | |||
| 87 | // from final- to strong mark. | |||
| 88 | if (task->count_liveness()) { | |||
| 89 | count_liveness(live_data, obj); | |||
| 90 | } | |||
| 91 | } else { | |||
| 92 | // Case 4: Array chunk, has sensible chunk id. Process it. | |||
| 93 | do_chunked_array<T>(q, cl, obj, task->chunk(), task->pow(), weak); | |||
| 94 | } | |||
| 95 | } | |||
| 96 | ||||
| 97 | inline void ShenandoahMark::count_liveness(ShenandoahLiveData* live_data, oop obj) { | |||
| 98 | ShenandoahHeap* const heap = ShenandoahHeap::heap(); | |||
| 99 | size_t region_idx = heap->heap_region_index_containing(obj); | |||
| 100 | ShenandoahHeapRegion* region = heap->get_region(region_idx); | |||
| 101 | size_t size = obj->size(); | |||
| 102 | ||||
| 103 | if (!region->is_humongous_start()) { | |||
| 104 | assert(!region->is_humongous(), "Cannot have continuations here")do { if (!(!region->is_humongous())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 104, "assert(" "!region->is_humongous()" ") failed", "Cannot have continuations here" ); ::breakpoint(); } } while (0); | |||
| 105 | ShenandoahLiveData cur = live_data[region_idx]; | |||
| 106 | size_t new_val = size + cur; | |||
| 107 | if (new_val >= SHENANDOAH_LIVEDATA_MAX((ShenandoahLiveData)-1)) { | |||
| 108 | // overflow, flush to region data | |||
| 109 | region->increase_live_data_gc_words(new_val); | |||
| 110 | live_data[region_idx] = 0; | |||
| 111 | } else { | |||
| 112 | // still good, remember in locals | |||
| 113 | live_data[region_idx] = (ShenandoahLiveData) new_val; | |||
| 114 | } | |||
| 115 | } else { | |||
| 116 | shenandoah_assert_in_correct_region(NULL, obj)ShenandoahAsserts::assert_in_correct_region(__null, obj, "/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 116); | |||
| 117 | size_t num_regions = ShenandoahHeapRegion::required_regions(size * HeapWordSize); | |||
| 118 | ||||
| 119 | for (size_t i = region_idx; i < region_idx + num_regions; i++) { | |||
| 120 | ShenandoahHeapRegion* chain_reg = heap->get_region(i); | |||
| 121 | assert(chain_reg->is_humongous(), "Expecting a humongous region")do { if (!(chain_reg->is_humongous())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 121, "assert(" "chain_reg->is_humongous()" ") failed", "Expecting a humongous region" ); ::breakpoint(); } } while (0); | |||
| 122 | chain_reg->increase_live_data_gc_words(chain_reg->used() >> LogHeapWordSize); | |||
| 123 | } | |||
| 124 | } | |||
| 125 | } | |||
| 126 | ||||
| 127 | template <class T> | |||
| 128 | inline void ShenandoahMark::do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop obj, bool weak) { | |||
| 129 | assert(obj->is_objArray(), "expect object array")do { if (!(obj->is_objArray())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 129, "assert(" "obj->is_objArray()" ") failed", "expect object array" ); ::breakpoint(); } } while (0); | |||
| 130 | objArrayOop array = objArrayOop(obj); | |||
| 131 | int len = array->length(); | |||
| 132 | ||||
| 133 | // Mark objArray klass metadata | |||
| 134 | if (Devirtualizer::do_metadata(cl)) { | |||
| 135 | Devirtualizer::do_klass(cl, array->klass()); | |||
| 136 | } | |||
| 137 | ||||
| 138 | if (len <= (int) ObjArrayMarkingStride*2) { | |||
| 139 | // A few slices only, process directly | |||
| 140 | array->oop_iterate_range(cl, 0, len); | |||
| 141 | } else { | |||
| 142 | int bits = log2i_graceful(len); | |||
| 143 | // Compensate for non-power-of-two arrays, cover the array in excess: | |||
| 144 | if (len != (1 << bits)) bits++; | |||
| ||||
| 145 | ||||
| 146 | // Only allow full chunks on the queue. This frees do_chunked_array() from checking from/to | |||
| 147 | // boundaries against array->length(), touching the array header on every chunk. | |||
| 148 | // | |||
| 149 | // To do this, we cut the prefix in full-sized chunks, and submit them on the queue. | |||
| 150 | // If the array is not divided in chunk sizes, then there would be an irregular tail, | |||
| 151 | // which we will process separately. | |||
| 152 | ||||
| 153 | int last_idx = 0; | |||
| 154 | ||||
| 155 | int chunk = 1; | |||
| 156 | int pow = bits; | |||
| 157 | ||||
| 158 | // Handle overflow | |||
| 159 | if (pow >= 31) { | |||
| 160 | assert (pow == 31, "sanity")do { if (!(pow == 31)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 160, "assert(" "pow == 31" ") failed", "sanity"); ::breakpoint (); } } while (0); | |||
| 161 | pow--; | |||
| 162 | chunk = 2; | |||
| 163 | last_idx = (1 << pow); | |||
| 164 | bool pushed = q->push(ShenandoahMarkTask(array, true, weak, 1, pow)); | |||
| 165 | assert(pushed, "overflow queue should always succeed pushing")do { if (!(pushed)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 165, "assert(" "pushed" ") failed", "overflow queue should always succeed pushing" ); ::breakpoint(); } } while (0); | |||
| 166 | } | |||
| 167 | ||||
| 168 | // Split out tasks, as suggested in ShenandoahMarkTask docs. Record the last | |||
| 169 | // successful right boundary to figure out the irregular tail. | |||
| 170 | while ((1 << pow) > (int)ObjArrayMarkingStride && | |||
| 171 | (chunk*2 < ShenandoahMarkTask::chunk_size())) { | |||
| 172 | pow--; | |||
| 173 | int left_chunk = chunk*2 - 1; | |||
| 174 | int right_chunk = chunk*2; | |||
| 175 | int left_chunk_end = left_chunk * (1 << pow); | |||
| 176 | if (left_chunk_end < len) { | |||
| 177 | bool pushed = q->push(ShenandoahMarkTask(array, true, weak, left_chunk, pow)); | |||
| 178 | assert(pushed, "overflow queue should always succeed pushing")do { if (!(pushed)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 178, "assert(" "pushed" ") failed", "overflow queue should always succeed pushing" ); ::breakpoint(); } } while (0); | |||
| 179 | chunk = right_chunk; | |||
| 180 | last_idx = left_chunk_end; | |||
| 181 | } else { | |||
| 182 | chunk = left_chunk; | |||
| 183 | } | |||
| 184 | } | |||
| 185 | ||||
| 186 | // Process the irregular tail, if present | |||
| 187 | int from = last_idx; | |||
| 188 | if (from < len) { | |||
| 189 | array->oop_iterate_range(cl, from, len); | |||
| 190 | } | |||
| 191 | } | |||
| 192 | } | |||
| 193 | ||||
| 194 | template <class T> | |||
| 195 | inline void ShenandoahMark::do_chunked_array(ShenandoahObjToScanQueue* q, T* cl, oop obj, int chunk, int pow, bool weak) { | |||
| 196 | assert(obj->is_objArray(), "expect object array")do { if (!(obj->is_objArray())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 196, "assert(" "obj->is_objArray()" ") failed", "expect object array" ); ::breakpoint(); } } while (0); | |||
| 197 | objArrayOop array = objArrayOop(obj); | |||
| 198 | ||||
| 199 | assert (ObjArrayMarkingStride > 0, "sanity")do { if (!(ObjArrayMarkingStride > 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 199, "assert(" "ObjArrayMarkingStride > 0" ") failed", "sanity" ); ::breakpoint(); } } while (0); | |||
| 200 | ||||
| 201 | // Split out tasks, as suggested in ShenandoahMarkTask docs. Avoid pushing tasks that | |||
| 202 | // are known to start beyond the array. | |||
| 203 | while ((1 << pow) > (int)ObjArrayMarkingStride && (chunk*2 < ShenandoahMarkTask::chunk_size())) { | |||
| 204 | pow--; | |||
| 205 | chunk *= 2; | |||
| 206 | bool pushed = q->push(ShenandoahMarkTask(array, true, weak, chunk - 1, pow)); | |||
| 207 | assert(pushed, "overflow queue should always succeed pushing")do { if (!(pushed)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 207, "assert(" "pushed" ") failed", "overflow queue should always succeed pushing" ); ::breakpoint(); } } while (0); | |||
| 208 | } | |||
| 209 | ||||
| 210 | int chunk_size = 1 << pow; | |||
| 211 | ||||
| 212 | int from = (chunk - 1) * chunk_size; | |||
| 213 | int to = chunk * chunk_size; | |||
| 214 | ||||
| 215 | #ifdef ASSERT1 | |||
| 216 | int len = array->length(); | |||
| 217 | assert (0 <= from && from < len, "from is sane: %d/%d", from, len)do { if (!(0 <= from && from < len)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 217, "assert(" "0 <= from && from < len" ") failed" , "from is sane: %d/%d", from, len); ::breakpoint(); } } while (0); | |||
| 218 | assert (0 < to && to <= len, "to is sane: %d/%d", to, len)do { if (!(0 < to && to <= len)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 218, "assert(" "0 < to && to <= len" ") failed" , "to is sane: %d/%d", to, len); ::breakpoint(); } } while (0 ); | |||
| 219 | #endif | |||
| 220 | ||||
| 221 | array->oop_iterate_range(cl, from, to); | |||
| 222 | } | |||
| 223 | ||||
| 224 | class ShenandoahSATBBufferClosure : public SATBBufferClosure { | |||
| 225 | private: | |||
| 226 | ShenandoahObjToScanQueue* _queue; | |||
| 227 | ShenandoahHeap* _heap; | |||
| 228 | ShenandoahMarkingContext* const _mark_context; | |||
| 229 | public: | |||
| 230 | ShenandoahSATBBufferClosure(ShenandoahObjToScanQueue* q) : | |||
| 231 | _queue(q), | |||
| 232 | _heap(ShenandoahHeap::heap()), | |||
| 233 | _mark_context(_heap->marking_context()) | |||
| 234 | { | |||
| 235 | } | |||
| 236 | ||||
| 237 | void do_buffer(void **buffer, size_t size) { | |||
| 238 | assert(size == 0 || !_heap->has_forwarded_objects(), "Forwarded objects are not expected here")do { if (!(size == 0 || !_heap->has_forwarded_objects())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 238, "assert(" "size == 0 || !_heap->has_forwarded_objects()" ") failed", "Forwarded objects are not expected here"); ::breakpoint (); } } while (0); | |||
| 239 | for (size_t i = 0; i < size; ++i) { | |||
| 240 | oop *p = (oop *) &buffer[i]; | |||
| 241 | ShenandoahMark::mark_through_ref<oop>(p, _queue, _mark_context, false); | |||
| 242 | } | |||
| 243 | } | |||
| 244 | }; | |||
| 245 | ||||
| 246 | template<class T> | |||
| 247 | inline void ShenandoahMark::mark_through_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak) { | |||
| 248 | T o = RawAccess<>::oop_load(p); | |||
| 249 | if (!CompressedOops::is_null(o)) { | |||
| 250 | oop obj = CompressedOops::decode_not_null(o); | |||
| 251 | ||||
| 252 | shenandoah_assert_not_forwarded(p, obj)ShenandoahAsserts::assert_not_forwarded(p, obj, "/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 252); | |||
| 253 | shenandoah_assert_not_in_cset_except(p, obj, ShenandoahHeap::heap()->cancelled_gc())if (!(ShenandoahHeap::heap()->cancelled_gc())) ShenandoahAsserts ::assert_not_in_cset(p, obj, "/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 253); | |||
| 254 | ||||
| 255 | bool skip_live = false; | |||
| 256 | bool marked; | |||
| 257 | if (weak) { | |||
| 258 | marked = mark_context->mark_weak(obj); | |||
| 259 | } else { | |||
| 260 | marked = mark_context->mark_strong(obj, /* was_upgraded = */ skip_live); | |||
| 261 | } | |||
| 262 | if (marked) { | |||
| 263 | bool pushed = q->push(ShenandoahMarkTask(obj, skip_live, weak)); | |||
| 264 | assert(pushed, "overflow queue should always succeed pushing")do { if (!(pushed)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 264, "assert(" "pushed" ") failed", "overflow queue should always succeed pushing" ); ::breakpoint(); } } while (0); | |||
| 265 | } | |||
| 266 | ||||
| 267 | shenandoah_assert_marked(p, obj)ShenandoahAsserts::assert_marked(p, obj, "/home/daniel/Projects/java/jdk/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp" , 267); | |||
| 268 | } | |||
| 269 | } | |||
| 270 | ||||
| 271 | ShenandoahObjToScanQueueSet* ShenandoahMark::task_queues() const { | |||
| 272 | return _task_queues; | |||
| 273 | } | |||
| 274 | ||||
| 275 | ShenandoahObjToScanQueue* ShenandoahMark::get_queue(uint index) const { | |||
| 276 | return _task_queues->queue(index); | |||
| 277 | } | |||
| 278 | #endif // SHARE_GC_SHENANDOAH_SHENANDOAHMARK_INLINE_HPP |
| 1 | /* |
| 2 | * Copyright (c) 2019, 2020, 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 | |
| 25 | #ifndef SHARE_UTILITIES_POWEROFTWO_HPP |
| 26 | #define SHARE_UTILITIES_POWEROFTWO_HPP |
| 27 | |
| 28 | #include "metaprogramming/enableIf.hpp" |
| 29 | #include "utilities/count_leading_zeros.hpp" |
| 30 | #include "utilities/count_trailing_zeros.hpp" |
| 31 | #include "utilities/debug.hpp" |
| 32 | #include "utilities/globalDefinitions.hpp" |
| 33 | #include <limits> |
| 34 | #include <type_traits> |
| 35 | |
| 36 | // Power of two convenience library. |
| 37 | |
| 38 | template <typename T, ENABLE_IF(std::is_integral<T>::value)std::enable_if_t<bool(std::is_integral<T>::value), int > = 0> |
| 39 | constexpr T max_power_of_2() { |
| 40 | T max_val = std::numeric_limits<T>::max(); |
| 41 | return max_val - (max_val >> 1); |
| 42 | } |
| 43 | |
| 44 | // Returns true iff there exists integer i such that (T(1) << i) == value. |
| 45 | template <typename T, ENABLE_IF(std::is_integral<T>::value)std::enable_if_t<bool(std::is_integral<T>::value), int > = 0> |
| 46 | constexpr bool is_power_of_2(T value) { |
| 47 | return (value > T(0)) && ((value & (value - 1)) == T(0)); |
| 48 | } |
| 49 | |
| 50 | // Log2 of a positive, integral value, i.e., largest i such that 2^i <= value |
| 51 | // Precondition: value > 0 |
| 52 | template<typename T, ENABLE_IF(std::is_integral<T>::value)std::enable_if_t<bool(std::is_integral<T>::value), int > = 0> |
| 53 | inline int log2i(T value) { |
| 54 | assert(value > T(0), "value must be > 0")do { if (!(value > T(0))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/powerOfTwo.hpp" , 54, "assert(" "value > T(0)" ") failed", "value must be > 0" ); ::breakpoint(); } } while (0); |
| 55 | const int bits = sizeof(value) * BitsPerByte; |
| 56 | return bits - count_leading_zeros(value) - 1; |
| 57 | } |
| 58 | |
| 59 | // Log2 of positive, integral value, i.e., largest i such that 2^i <= value |
| 60 | // Returns -1 if value is zero |
| 61 | // For negative values this will return 63 for 64-bit types, 31 for |
| 62 | // 32-bit types, and so on. |
| 63 | template<typename T, ENABLE_IF(std::is_integral<T>::value)std::enable_if_t<bool(std::is_integral<T>::value), int > = 0> |
| 64 | inline int log2i_graceful(T value) { |
| 65 | if (value == 0) { |
| 66 | return -1; |
| 67 | } |
| 68 | const int bits = sizeof(value) * BitsPerByte; |
| 69 | return bits - count_leading_zeros(value) - 1; |
| 70 | } |
| 71 | |
| 72 | // Log2 of a power of 2, i.e., i such that 2^i == value |
| 73 | // Preconditions: value > 0, value is a power of two |
| 74 | template<typename T, ENABLE_IF(std::is_integral<T>::value)std::enable_if_t<bool(std::is_integral<T>::value), int > = 0> |
| 75 | inline int log2i_exact(T value) { |
| 76 | assert(is_power_of_2(value),do { if (!(is_power_of_2(value))) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/powerOfTwo.hpp" , 78, "assert(" "is_power_of_2(value)" ") failed", "value must be a power of 2: " "%" "l" "x", static_cast<uint64_t>(value)); ::breakpoint (); } } while (0) |
| 77 | "value must be a power of 2: " UINT64_FORMAT_X,do { if (!(is_power_of_2(value))) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/powerOfTwo.hpp" , 78, "assert(" "is_power_of_2(value)" ") failed", "value must be a power of 2: " "%" "l" "x", static_cast<uint64_t>(value)); ::breakpoint (); } } while (0) |
| 78 | static_cast<uint64_t>(value))do { if (!(is_power_of_2(value))) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/powerOfTwo.hpp" , 78, "assert(" "is_power_of_2(value)" ") failed", "value must be a power of 2: " "%" "l" "x", static_cast<uint64_t>(value)); ::breakpoint (); } } while (0); |
| 79 | return count_trailing_zeros(value); |
| 80 | } |
| 81 | |
| 82 | // Preconditions: value != 0, and the unsigned representation of value is a power of two |
| 83 | inline int exact_log2(intptr_t value) { |
| 84 | return log2i_exact((uintptr_t)value); |
| 85 | } |
| 86 | |
| 87 | // Preconditions: value != 0, and the unsigned representation of value is a power of two |
| 88 | inline int exact_log2_long(jlong value) { |
| 89 | return log2i_exact((julong)value); |
| 90 | } |
| 91 | |
| 92 | // Round down to the closest power of two less than or equal to the given value. |
| 93 | // precondition: value > 0. |
| 94 | template<typename T, ENABLE_IF(std::is_integral<T>::value)std::enable_if_t<bool(std::is_integral<T>::value), int > = 0> |
| 95 | inline T round_down_power_of_2(T value) { |
| 96 | assert(value > 0, "Invalid value")do { if (!(value > 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/powerOfTwo.hpp" , 96, "assert(" "value > 0" ") failed", "Invalid value"); :: breakpoint(); } } while (0); |
| 97 | return T(1) << log2i(value); |
| 98 | } |
| 99 | |
| 100 | // Round up to the closest power of two greater to or equal to the given value. |
| 101 | // precondition: value > 0. |
| 102 | // precondition: value <= maximum power of two representable by T. |
| 103 | template<typename T, ENABLE_IF(std::is_integral<T>::value)std::enable_if_t<bool(std::is_integral<T>::value), int > = 0> |
| 104 | inline T round_up_power_of_2(T value) { |
| 105 | assert(value > 0, "Invalid value")do { if (!(value > 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/powerOfTwo.hpp" , 105, "assert(" "value > 0" ") failed", "Invalid value"); ::breakpoint(); } } while (0); |
| 106 | assert(value <= max_power_of_2<T>(), "Overflow")do { if (!(value <= max_power_of_2<T>())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/powerOfTwo.hpp" , 106, "assert(" "value <= max_power_of_2<T>()" ") failed" , "Overflow"); ::breakpoint(); } } while (0); |
| 107 | if (is_power_of_2(value)) { |
| 108 | return value; |
| 109 | } |
| 110 | return T(1) << (log2i(value) + 1); |
| 111 | } |
| 112 | |
| 113 | // Calculate the next power of two greater than the given value. |
| 114 | // precondition: if signed, value >= 0. |
| 115 | // precondition: value < maximum power of two representable by T. |
| 116 | template <typename T, ENABLE_IF(std::is_integral<T>::value)std::enable_if_t<bool(std::is_integral<T>::value), int > = 0> |
| 117 | inline T next_power_of_2(T value) { |
| 118 | assert(value < std::numeric_limits<T>::max(), "Overflow")do { if (!(value < std::numeric_limits<T>::max())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/powerOfTwo.hpp" , 118, "assert(" "value < std::numeric_limits<T>::max()" ") failed", "Overflow"); ::breakpoint(); } } while (0); |
| 119 | return round_up_power_of_2(value + 1); |
| 120 | } |
| 121 | |
| 122 | #endif // SHARE_UTILITIES_POWEROFTWO_HPP |