1 /* 2 * Copyright (c) 2016, 2017, 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 #include "precompiled.hpp" 26 #include "gc/shared/preservedMarks.inline.hpp" 27 #include "gc/shared/workgroup.hpp" 28 #include "memory/allocation.inline.hpp" 29 #include "memory/resourceArea.hpp" 30 #include "utilities/macros.hpp" 31 32 void PreservedMarks::restore() { 33 while (!_stack.is_empty()) { 34 const OopAndMarkOop elem = _stack.pop(); 35 elem.set_mark(); 36 } 37 assert_empty(); 38 } 39 40 void PreservedMarks::adjust_during_full_gc() { 41 StackIterator<OopAndMarkOop, mtGC> iter(_stack); 42 while (!iter.is_empty()) { 43 OopAndMarkOop* elem = iter.next_addr(); 44 45 oop obj = elem->get_oop(); 46 if (obj->is_forwarded()) { 47 elem->set_oop(obj->forwardee()); 48 } 49 } 50 } 51 52 void PreservedMarks::restore_and_increment(volatile size_t* const total_size_addr) { 53 const size_t stack_size = size(); 54 restore(); 55 // Only do the atomic add if the size is > 0. 56 if (stack_size > 0) { 57 Atomic::add(stack_size, total_size_addr); 58 } 59 } 60 61 #ifndef PRODUCT 62 void PreservedMarks::assert_empty() { 63 assert(_stack.is_empty(), "stack expected to be empty, size = " SIZE_FORMAT, 64 _stack.size()); 65 assert(_stack.cache_size() == 0, 66 "stack expected to have no cached segments, cache size = " SIZE_FORMAT, 67 _stack.cache_size()); 68 } 69 #endif // ndef PRODUCT 70 71 void RemoveForwardedPointerClosure::do_object(oop obj) { 72 if (obj->is_forwarded()) { 73 PreservedMarks::init_forwarded_mark(obj); 74 } 75 } 76 77 void PreservedMarksSet::init(uint num) { 78 assert(_stacks == NULL && _num == 0, "do not re-initialize"); 79 assert(num > 0, "pre-condition"); 80 if (_in_c_heap) { 81 _stacks = NEW_C_HEAP_ARRAY(Padded<PreservedMarks>, num, mtGC); 82 } else { 83 _stacks = NEW_RESOURCE_ARRAY(Padded<PreservedMarks>, num); 84 } 85 for (uint i = 0; i < num; i += 1) { 86 ::new (_stacks + i) PreservedMarks(); 87 } 88 _num = num; 89 90 assert_empty(); 91 } 92 93 class ParRestoreTask : public AbstractGangTask { 94 private: 95 PreservedMarksSet* const _preserved_marks_set; 96 SequentialSubTasksDone _sub_tasks; 97 volatile size_t* const _total_size_addr; 98 99 public: 100 virtual void work(uint worker_id) { 101 uint task_id = 0; 102 while (!_sub_tasks.is_task_claimed(/* reference */ task_id)) { 103 _preserved_marks_set->get(task_id)->restore_and_increment(_total_size_addr); 104 } 105 _sub_tasks.all_tasks_completed(); 106 } 107 108 ParRestoreTask(uint worker_num, 109 PreservedMarksSet* preserved_marks_set, 110 volatile size_t* total_size_addr) 111 : AbstractGangTask("Parallel Preserved Mark Restoration"), 112 _preserved_marks_set(preserved_marks_set), 113 _total_size_addr(total_size_addr) { 114 _sub_tasks.set_n_threads(worker_num); 115 _sub_tasks.set_n_tasks(preserved_marks_set->num()); 116 } 117 }; 118 119 void PreservedMarksSet::reclaim() { 120 assert_empty(); 121 122 for (uint i = 0; i < _num; i += 1) { 123 _stacks[i].~Padded<PreservedMarks>(); 124 } 125 126 if (_in_c_heap) { 127 FREE_C_HEAP_ARRAY(Padded<PreservedMarks>, _stacks); 128 } else { 129 // the array was resource-allocated, so nothing to do 130 } 131 _stacks = NULL; 132 _num = 0; 133 } 134 135 #ifndef PRODUCT 136 void PreservedMarksSet::assert_empty() { 137 assert(_stacks != NULL && _num > 0, "should have been initialized"); 138 for (uint i = 0; i < _num; i += 1) { 139 get(i)->assert_empty(); 140 } 141 } 142 #endif // ndef PRODUCT 143 144 void SharedRestorePreservedMarksTaskExecutor::restore(PreservedMarksSet* preserved_marks_set, 145 volatile size_t* total_size_addr) { 146 if (_workers == NULL) { 147 for (uint i = 0; i < preserved_marks_set->num(); i += 1) { 148 *total_size_addr += preserved_marks_set->get(i)->size(); 149 preserved_marks_set->get(i)->restore(); 150 } 151 } else { 152 ParRestoreTask task(_workers->active_workers(), preserved_marks_set, total_size_addr); 153 _workers->run_task(&task); 154 } 155 }