/* * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #include "precompiled.hpp" #include "gc/g1/bufferingOopClosure.hpp" #include "memory/iterator.hpp" #include "unittest.hpp" class BufferingOopClosureTest : public ::testing::Test { public: // Helper class to fake a set of oop*s and narrowOop*s. class FakeRoots { public: // Used for sanity checking of the values passed to the do_oops functions in the test. static const uintptr_t NarrowOopMarker = uintptr_t(1) << (BitsPerWord -1); int _num_narrow; int _num_full; void** _narrow; void** _full; FakeRoots(int num_narrow, int num_full) : _num_narrow(num_narrow), _num_full(num_full), _narrow((void**)::malloc(sizeof(void*) * num_narrow)), _full((void**)::malloc(sizeof(void*) * num_full)) { for (int i = 0; i < num_narrow; i++) { _narrow[i] = (void*)(NarrowOopMarker + (uintptr_t)i); } for (int i = 0; i < num_full; i++) { _full[i] = (void*)(uintptr_t)i; } } ~FakeRoots() { ::free(_narrow); ::free(_full); } void oops_do_narrow_then_full(OopClosure* cl) { for (int i = 0; i < _num_narrow; i++) { cl->do_oop((narrowOop*)_narrow[i]); } for (int i = 0; i < _num_full; i++) { cl->do_oop((oop*)_full[i]); } } void oops_do_full_then_narrow(OopClosure* cl) { for (int i = 0; i < _num_full; i++) { cl->do_oop((oop*)_full[i]); } for (int i = 0; i < _num_narrow; i++) { cl->do_oop((narrowOop*)_narrow[i]); } } void oops_do_mixed(OopClosure* cl) { int i; for (i = 0; i < _num_full && i < _num_narrow; i++) { cl->do_oop((oop*)_full[i]); cl->do_oop((narrowOop*)_narrow[i]); } for (int j = i; j < _num_full; j++) { cl->do_oop((oop*)_full[i]); } for (int j = i; j < _num_narrow; j++) { cl->do_oop((narrowOop*)_narrow[i]); } } static const int MaxOrder = 2; void oops_do(OopClosure* cl, int do_oop_order) { switch(do_oop_order) { case 0: oops_do_narrow_then_full(cl); break; case 1: oops_do_full_then_narrow(cl); break; case 2: oops_do_mixed(cl); break; default: oops_do_narrow_then_full(cl); break; } } }; class CountOopClosure : public OopClosure { int _narrow_oop_count; int _full_oop_count; public: CountOopClosure() : _narrow_oop_count(0), _full_oop_count(0) {} void do_oop(narrowOop* p) { EXPECT_NE(uintptr_t(0), (uintptr_t(p) & FakeRoots::NarrowOopMarker)) << "The narrowOop was unexpectedly not marked with the NarrowOopMarker"; _narrow_oop_count++; } void do_oop(oop* p){ EXPECT_EQ(uintptr_t(0), (uintptr_t(p) & FakeRoots::NarrowOopMarker)) << "The oop was unexpectedly marked with the NarrowOopMarker"; _full_oop_count++; } int narrow_oop_count() { return _narrow_oop_count; } int full_oop_count() { return _full_oop_count; } int all_oop_count() { return _narrow_oop_count + _full_oop_count; } }; class DoNothingOopClosure : public OopClosure { public: void do_oop(narrowOop* p) {} void do_oop(oop* p) {} }; static void testCount(int num_narrow, int num_full, int do_oop_order) { FakeRoots fr(num_narrow, num_full); CountOopClosure coc; BufferingOopClosure boc(&coc); fr.oops_do(&boc, do_oop_order); boc.done(); EXPECT_EQ(num_narrow, coc.narrow_oop_count()) << "when running testCount(" << num_narrow << ", " << num_full << ", " << do_oop_order << ")"; EXPECT_EQ(num_full, coc.full_oop_count()) << "when running testCount(" << num_narrow << ", " << num_full << ", " << do_oop_order << ")"; EXPECT_EQ(num_narrow + num_full, coc.all_oop_count()) << "when running testCount(" << num_narrow << ", " << num_full << ", " << do_oop_order << ")"; } static void testIsBufferEmptyOrFull(int num_narrow, int num_full, bool expect_empty, bool expect_full) { FakeRoots fr(num_narrow, num_full); DoNothingOopClosure cl; BufferingOopClosure boc(&cl); fr.oops_do(&boc, 0); EXPECT_EQ(expect_empty, boc.is_buffer_empty()) << "when running testIsBufferEmptyOrFull(" << num_narrow << ", " << num_full << ", " << expect_empty << ", " << expect_full << ")"; EXPECT_EQ(expect_full, boc.is_buffer_full()) << "when running testIsBufferEmptyOrFull(" << num_narrow << ", " << num_full << ", " << expect_empty << ", " << expect_full << ")"; } static void testEmptyAfterDone(int num_narrow, int num_full) { FakeRoots fr(num_narrow, num_full); DoNothingOopClosure cl; BufferingOopClosure boc(&cl); fr.oops_do(&boc, 0); // Make sure all get processed. boc.done(); EXPECT_TRUE(boc.is_buffer_empty()) << "Should be empty after call to done()." << " testEmptyAfterDone(" << num_narrow << ", " << num_full << ")"; } static int get_buffer_length() { return BufferingOopClosure::BufferLength; } }; TEST_VM_F(BufferingOopClosureTest, count_test) { int bl = BufferingOopClosureTest::get_buffer_length(); for (int order = 0; order < FakeRoots::MaxOrder; order++) { testCount(0, 0, order); testCount(10, 0, order); testCount(0, 10, order); testCount(10, 10, order); testCount(bl, 10, order); testCount(10, bl, order); testCount(bl, bl, order); testCount(bl + 1, 10, order); testCount(10, bl + 1, order); testCount(bl + 1, bl, order); testCount(bl, bl + 1, order); testCount(bl + 1, bl + 1, order); } } TEST_VM_F(BufferingOopClosureTest, buffer_empty_or_full) { int bl = BufferingOopClosureTest::get_buffer_length(); testIsBufferEmptyOrFull(0, 0, true, false); testIsBufferEmptyOrFull(1, 0, false, false); testIsBufferEmptyOrFull(0, 1, false, false); testIsBufferEmptyOrFull(1, 1, false, false); testIsBufferEmptyOrFull(10, 0, false, false); testIsBufferEmptyOrFull(0, 10, false, false); testIsBufferEmptyOrFull(10, 10, false, false); testIsBufferEmptyOrFull(0, bl, false, true); testIsBufferEmptyOrFull(bl, 0, false, true); testIsBufferEmptyOrFull(bl / 2, bl / 2, false, true); testIsBufferEmptyOrFull(bl - 1, 1, false, true); testIsBufferEmptyOrFull(1, bl - 1, false, true); // Processed testIsBufferEmptyOrFull(bl + 1, 0, false, false); testIsBufferEmptyOrFull(bl * 2, 0, false, true); } TEST_VM_F(BufferingOopClosureTest, empty_after_done) { int bl = BufferingOopClosureTest::get_buffer_length(); testEmptyAfterDone(0, 0); testEmptyAfterDone(1, 0); testEmptyAfterDone(0, 1); testEmptyAfterDone(1, 1); testEmptyAfterDone(10, 0); testEmptyAfterDone(0, 10); testEmptyAfterDone(10, 10); testEmptyAfterDone(0, bl); testEmptyAfterDone(bl, 0); testEmptyAfterDone(bl / 2, bl / 2); testEmptyAfterDone(bl - 1, 1); testEmptyAfterDone(1, bl - 1); // Processed testEmptyAfterDone(bl + 1, 0); testEmptyAfterDone(bl * 2, 0); }