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 |