Mon, 08 Dec 2014 18:57:33 +0100
8067655: Clean up G1 remembered set oop iteration
Summary: Pass on the static type G1ParPushHeapRSClosure to allow oop_iterate devirtualization
Reviewed-by: jmasa, kbarrett
stefank@6969 | 1 | /* |
stefank@6969 | 2 | * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. |
stefank@6969 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
stefank@6969 | 4 | * |
stefank@6969 | 5 | * This code is free software; you can redistribute it and/or modify it |
stefank@6969 | 6 | * under the terms of the GNU General Public License version 2 only, as |
stefank@6969 | 7 | * published by the Free Software Foundation. |
stefank@6969 | 8 | * |
stefank@6969 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
stefank@6969 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
stefank@6969 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
stefank@6969 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
stefank@6969 | 13 | * accompanied this code). |
stefank@6969 | 14 | * |
stefank@6969 | 15 | * You should have received a copy of the GNU General Public License version |
stefank@6969 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
stefank@6969 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
stefank@6969 | 18 | * |
stefank@6969 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
stefank@6969 | 20 | * or visit www.oracle.com if you need additional information or have any |
stefank@6969 | 21 | * questions. |
stefank@6969 | 22 | * |
stefank@6969 | 23 | */ |
stefank@6969 | 24 | |
stefank@6969 | 25 | #include "precompiled.hpp" |
stefank@6969 | 26 | #include "gc_implementation/g1/bufferingOopClosure.hpp" |
stefank@6969 | 27 | #include "memory/iterator.hpp" |
stefank@6969 | 28 | #include "utilities/debug.hpp" |
stefank@6969 | 29 | |
stefank@6969 | 30 | /////////////// Unit tests /////////////// |
stefank@6969 | 31 | |
stefank@6969 | 32 | #ifndef PRODUCT |
stefank@6969 | 33 | |
stefank@6969 | 34 | class TestBufferingOopClosure { |
stefank@6969 | 35 | |
stefank@6969 | 36 | // Helper class to fake a set of oop*s and narrowOop*s. |
stefank@6969 | 37 | class FakeRoots { |
stefank@6969 | 38 | public: |
stefank@6969 | 39 | // Used for sanity checking of the values passed to the do_oops functions in the test. |
stefank@6969 | 40 | static const uintptr_t NarrowOopMarker = uintptr_t(1) << (BitsPerWord -1); |
stefank@6969 | 41 | |
stefank@6969 | 42 | int _num_narrow; |
stefank@6969 | 43 | int _num_full; |
stefank@6969 | 44 | void** _narrow; |
stefank@6969 | 45 | void** _full; |
stefank@6969 | 46 | |
stefank@6969 | 47 | FakeRoots(int num_narrow, int num_full) : |
stefank@6969 | 48 | _num_narrow(num_narrow), |
stefank@6969 | 49 | _num_full(num_full), |
stefank@6969 | 50 | _narrow((void**)::malloc(sizeof(void*) * num_narrow)), |
stefank@6969 | 51 | _full((void**)::malloc(sizeof(void*) * num_full)) { |
stefank@6969 | 52 | |
stefank@6969 | 53 | for (int i = 0; i < num_narrow; i++) { |
stefank@6969 | 54 | _narrow[i] = (void*)(NarrowOopMarker + (uintptr_t)i); |
stefank@6969 | 55 | } |
stefank@6969 | 56 | for (int i = 0; i < num_full; i++) { |
stefank@6969 | 57 | _full[i] = (void*)(uintptr_t)i; |
stefank@6969 | 58 | } |
stefank@6969 | 59 | } |
stefank@6969 | 60 | |
stefank@6969 | 61 | ~FakeRoots() { |
stefank@6969 | 62 | ::free(_narrow); |
stefank@6969 | 63 | ::free(_full); |
stefank@6969 | 64 | } |
stefank@6969 | 65 | |
stefank@6969 | 66 | void oops_do_narrow_then_full(OopClosure* cl) { |
stefank@6969 | 67 | for (int i = 0; i < _num_narrow; i++) { |
stefank@6969 | 68 | cl->do_oop((narrowOop*)_narrow[i]); |
stefank@6969 | 69 | } |
stefank@6969 | 70 | for (int i = 0; i < _num_full; i++) { |
stefank@6969 | 71 | cl->do_oop((oop*)_full[i]); |
stefank@6969 | 72 | } |
stefank@6969 | 73 | } |
stefank@6969 | 74 | |
stefank@6969 | 75 | void oops_do_full_then_narrow(OopClosure* cl) { |
stefank@6969 | 76 | for (int i = 0; i < _num_full; i++) { |
stefank@6969 | 77 | cl->do_oop((oop*)_full[i]); |
stefank@6969 | 78 | } |
stefank@6969 | 79 | for (int i = 0; i < _num_narrow; i++) { |
stefank@6969 | 80 | cl->do_oop((narrowOop*)_narrow[i]); |
stefank@6969 | 81 | } |
stefank@6969 | 82 | } |
stefank@6969 | 83 | |
stefank@6969 | 84 | void oops_do_mixed(OopClosure* cl) { |
stefank@6969 | 85 | int i; |
stefank@6969 | 86 | for (i = 0; i < _num_full && i < _num_narrow; i++) { |
stefank@6969 | 87 | cl->do_oop((oop*)_full[i]); |
stefank@6969 | 88 | cl->do_oop((narrowOop*)_narrow[i]); |
stefank@6969 | 89 | } |
stefank@6969 | 90 | for (int j = i; j < _num_full; j++) { |
stefank@6969 | 91 | cl->do_oop((oop*)_full[i]); |
stefank@6969 | 92 | } |
stefank@6969 | 93 | for (int j = i; j < _num_narrow; j++) { |
stefank@6969 | 94 | cl->do_oop((narrowOop*)_narrow[i]); |
stefank@6969 | 95 | } |
stefank@6969 | 96 | } |
stefank@6969 | 97 | |
stefank@6969 | 98 | static const int MaxOrder = 2; |
stefank@6969 | 99 | |
stefank@6969 | 100 | void oops_do(OopClosure* cl, int do_oop_order) { |
stefank@6969 | 101 | switch(do_oop_order) { |
stefank@6969 | 102 | case 0: |
stefank@6969 | 103 | oops_do_narrow_then_full(cl); |
stefank@6969 | 104 | break; |
stefank@6969 | 105 | case 1: |
stefank@6969 | 106 | oops_do_full_then_narrow(cl); |
stefank@6969 | 107 | break; |
stefank@6969 | 108 | case 2: |
stefank@6969 | 109 | oops_do_mixed(cl); |
stefank@6969 | 110 | break; |
stefank@6969 | 111 | default: |
stefank@6969 | 112 | oops_do_narrow_then_full(cl); |
stefank@6969 | 113 | break; |
stefank@6969 | 114 | } |
stefank@6969 | 115 | } |
stefank@6969 | 116 | }; |
stefank@6969 | 117 | |
stefank@6969 | 118 | class CountOopClosure : public OopClosure { |
stefank@6969 | 119 | int _narrow_oop_count; |
stefank@6969 | 120 | int _full_oop_count; |
stefank@6969 | 121 | public: |
stefank@6969 | 122 | CountOopClosure() : _narrow_oop_count(0), _full_oop_count(0) {} |
stefank@6969 | 123 | void do_oop(narrowOop* p) { |
stefank@6969 | 124 | assert((uintptr_t(p) & FakeRoots::NarrowOopMarker) != 0, |
stefank@6969 | 125 | "The narrowOop was unexpectedly not marked with the NarrowOopMarker"); |
stefank@6969 | 126 | _narrow_oop_count++; |
stefank@6969 | 127 | } |
stefank@6969 | 128 | |
stefank@6969 | 129 | void do_oop(oop* p){ |
stefank@6969 | 130 | assert((uintptr_t(p) & FakeRoots::NarrowOopMarker) == 0, |
stefank@6969 | 131 | "The oop was unexpectedly marked with the NarrowOopMarker"); |
stefank@6969 | 132 | _full_oop_count++; |
stefank@6969 | 133 | } |
stefank@6969 | 134 | |
stefank@6969 | 135 | int narrow_oop_count() { return _narrow_oop_count; } |
stefank@6969 | 136 | int full_oop_count() { return _full_oop_count; } |
stefank@6969 | 137 | int all_oop_count() { return _narrow_oop_count + _full_oop_count; } |
stefank@6969 | 138 | }; |
stefank@6969 | 139 | |
stefank@6969 | 140 | class DoNothingOopClosure : public OopClosure { |
stefank@6969 | 141 | public: |
stefank@6969 | 142 | void do_oop(narrowOop* p) {} |
stefank@6969 | 143 | void do_oop(oop* p) {} |
stefank@6969 | 144 | }; |
stefank@6969 | 145 | |
stefank@6969 | 146 | static void testCount(int num_narrow, int num_full, int do_oop_order) { |
stefank@6969 | 147 | FakeRoots fr(num_narrow, num_full); |
stefank@6969 | 148 | |
stefank@6969 | 149 | CountOopClosure coc; |
stefank@6969 | 150 | BufferingOopClosure boc(&coc); |
stefank@6969 | 151 | |
stefank@6969 | 152 | fr.oops_do(&boc, do_oop_order); |
stefank@6969 | 153 | |
stefank@6969 | 154 | boc.done(); |
stefank@6969 | 155 | |
stefank@6969 | 156 | #define assert_testCount(got, expected) \ |
stefank@6969 | 157 | assert((got) == (expected), \ |
stefank@6969 | 158 | err_msg("Expected: %d, got: %d, when running testCount(%d, %d, %d)", \ |
stefank@6969 | 159 | (got), (expected), num_narrow, num_full, do_oop_order)) |
stefank@6969 | 160 | |
stefank@6969 | 161 | assert_testCount(num_narrow, coc.narrow_oop_count()); |
stefank@6969 | 162 | assert_testCount(num_full, coc.full_oop_count()); |
stefank@6969 | 163 | assert_testCount(num_narrow + num_full, coc.all_oop_count()); |
stefank@6969 | 164 | } |
stefank@6969 | 165 | |
stefank@6969 | 166 | static void testCount() { |
stefank@6969 | 167 | int buffer_length = BufferingOopClosure::BufferLength; |
stefank@6969 | 168 | |
stefank@6969 | 169 | for (int order = 0; order < FakeRoots::MaxOrder; order++) { |
stefank@6969 | 170 | testCount(0, 0, order); |
stefank@6969 | 171 | testCount(10, 0, order); |
stefank@6969 | 172 | testCount(0, 10, order); |
stefank@6969 | 173 | testCount(10, 10, order); |
stefank@6969 | 174 | testCount(buffer_length, 10, order); |
stefank@6969 | 175 | testCount(10, buffer_length, order); |
stefank@6969 | 176 | testCount(buffer_length, buffer_length, order); |
stefank@6969 | 177 | testCount(buffer_length + 1, 10, order); |
stefank@6969 | 178 | testCount(10, buffer_length + 1, order); |
stefank@6969 | 179 | testCount(buffer_length + 1, buffer_length, order); |
stefank@6969 | 180 | testCount(buffer_length, buffer_length + 1, order); |
stefank@6969 | 181 | testCount(buffer_length + 1, buffer_length + 1, order); |
stefank@6969 | 182 | } |
stefank@6969 | 183 | } |
stefank@6969 | 184 | |
stefank@6969 | 185 | static void testIsBufferEmptyOrFull(int num_narrow, int num_full, bool expect_empty, bool expect_full) { |
stefank@6969 | 186 | FakeRoots fr(num_narrow, num_full); |
stefank@6969 | 187 | |
stefank@6969 | 188 | DoNothingOopClosure cl; |
stefank@6969 | 189 | BufferingOopClosure boc(&cl); |
stefank@6969 | 190 | |
stefank@6969 | 191 | fr.oops_do(&boc, 0); |
stefank@6969 | 192 | |
stefank@6969 | 193 | #define assert_testIsBufferEmptyOrFull(got, expected) \ |
stefank@6969 | 194 | assert((got) == (expected), \ |
stefank@6969 | 195 | err_msg("Expected: %d, got: %d. testIsBufferEmptyOrFull(%d, %d, %s, %s)", \ |
stefank@6969 | 196 | (got), (expected), num_narrow, num_full, \ |
stefank@6969 | 197 | BOOL_TO_STR(expect_empty), BOOL_TO_STR(expect_full))) |
stefank@6969 | 198 | |
stefank@6969 | 199 | assert_testIsBufferEmptyOrFull(expect_empty, boc.is_buffer_empty()); |
stefank@6969 | 200 | assert_testIsBufferEmptyOrFull(expect_full, boc.is_buffer_full()); |
stefank@6969 | 201 | } |
stefank@6969 | 202 | |
stefank@6969 | 203 | static void testIsBufferEmptyOrFull() { |
stefank@6969 | 204 | int bl = BufferingOopClosure::BufferLength; |
stefank@6969 | 205 | |
stefank@6969 | 206 | testIsBufferEmptyOrFull(0, 0, true, false); |
stefank@6969 | 207 | testIsBufferEmptyOrFull(1, 0, false, false); |
stefank@6969 | 208 | testIsBufferEmptyOrFull(0, 1, false, false); |
stefank@6969 | 209 | testIsBufferEmptyOrFull(1, 1, false, false); |
stefank@6969 | 210 | testIsBufferEmptyOrFull(10, 0, false, false); |
stefank@6969 | 211 | testIsBufferEmptyOrFull(0, 10, false, false); |
stefank@6969 | 212 | testIsBufferEmptyOrFull(10, 10, false, false); |
stefank@6969 | 213 | testIsBufferEmptyOrFull(0, bl, false, true); |
stefank@6969 | 214 | testIsBufferEmptyOrFull(bl, 0, false, true); |
stefank@6969 | 215 | testIsBufferEmptyOrFull(bl/2, bl/2, false, true); |
stefank@6969 | 216 | testIsBufferEmptyOrFull(bl-1, 1, false, true); |
stefank@6969 | 217 | testIsBufferEmptyOrFull(1, bl-1, false, true); |
stefank@6969 | 218 | // Processed |
stefank@6969 | 219 | testIsBufferEmptyOrFull(bl+1, 0, false, false); |
stefank@6969 | 220 | testIsBufferEmptyOrFull(bl*2, 0, false, true); |
stefank@6969 | 221 | } |
stefank@6969 | 222 | |
stefank@6969 | 223 | static void testEmptyAfterDone(int num_narrow, int num_full) { |
stefank@6969 | 224 | FakeRoots fr(num_narrow, num_full); |
stefank@6969 | 225 | |
stefank@6969 | 226 | DoNothingOopClosure cl; |
stefank@6969 | 227 | BufferingOopClosure boc(&cl); |
stefank@6969 | 228 | |
stefank@6969 | 229 | fr.oops_do(&boc, 0); |
stefank@6969 | 230 | |
stefank@6969 | 231 | // Make sure all get processed. |
stefank@6969 | 232 | boc.done(); |
stefank@6969 | 233 | |
stefank@6969 | 234 | assert(boc.is_buffer_empty(), |
stefank@6969 | 235 | err_msg("Should be empty after call to done(). testEmptyAfterDone(%d, %d)", |
stefank@6969 | 236 | num_narrow, num_full)); |
stefank@6969 | 237 | } |
stefank@6969 | 238 | |
stefank@6969 | 239 | static void testEmptyAfterDone() { |
stefank@6969 | 240 | int bl = BufferingOopClosure::BufferLength; |
stefank@6969 | 241 | |
stefank@6969 | 242 | testEmptyAfterDone(0, 0); |
stefank@6969 | 243 | testEmptyAfterDone(1, 0); |
stefank@6969 | 244 | testEmptyAfterDone(0, 1); |
stefank@6969 | 245 | testEmptyAfterDone(1, 1); |
stefank@6969 | 246 | testEmptyAfterDone(10, 0); |
stefank@6969 | 247 | testEmptyAfterDone(0, 10); |
stefank@6969 | 248 | testEmptyAfterDone(10, 10); |
stefank@6969 | 249 | testEmptyAfterDone(0, bl); |
stefank@6969 | 250 | testEmptyAfterDone(bl, 0); |
stefank@6969 | 251 | testEmptyAfterDone(bl/2, bl/2); |
stefank@6969 | 252 | testEmptyAfterDone(bl-1, 1); |
stefank@6969 | 253 | testEmptyAfterDone(1, bl-1); |
stefank@6969 | 254 | // Processed |
stefank@6969 | 255 | testEmptyAfterDone(bl+1, 0); |
stefank@6969 | 256 | testEmptyAfterDone(bl*2, 0); |
stefank@6969 | 257 | } |
stefank@6969 | 258 | |
stefank@6969 | 259 | public: |
stefank@6969 | 260 | static void test() { |
stefank@6969 | 261 | testCount(); |
stefank@6969 | 262 | testIsBufferEmptyOrFull(); |
stefank@6969 | 263 | testEmptyAfterDone(); |
stefank@6969 | 264 | } |
stefank@6969 | 265 | }; |
stefank@6969 | 266 | |
stefank@6969 | 267 | void TestBufferingOopClosure_test() { |
stefank@6969 | 268 | TestBufferingOopClosure::test(); |
stefank@6969 | 269 | } |
stefank@6969 | 270 | |
stefank@6969 | 271 | #endif |