Wed, 22 Jan 2014 17:42:23 -0800
Merge
ysr@1876 | 1 | /* |
coleenp@4037 | 2 | * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. |
ysr@1876 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
ysr@1876 | 4 | * |
ysr@1876 | 5 | * This code is free software; you can redistribute it and/or modify it |
ysr@1876 | 6 | * under the terms of the GNU General Public License version 2 only, as |
ysr@1876 | 7 | * published by the Free Software Foundation. |
ysr@1876 | 8 | * |
ysr@1876 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
ysr@1876 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
ysr@1876 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
ysr@1876 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
ysr@1876 | 13 | * accompanied this code). |
ysr@1876 | 14 | * |
ysr@1876 | 15 | * You should have received a copy of the GNU General Public License version |
ysr@1876 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
ysr@1876 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
ysr@1876 | 18 | * |
trims@1907 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
trims@1907 | 20 | * or visit www.oracle.com if you need additional information or have any |
trims@1907 | 21 | * questions. |
ysr@1876 | 22 | * |
ysr@1876 | 23 | */ |
ysr@1876 | 24 | |
stefank@2314 | 25 | #ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_PROMOTIONINFO_HPP |
stefank@2314 | 26 | #define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_PROMOTIONINFO_HPP |
stefank@2314 | 27 | |
stefank@2314 | 28 | #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" |
stefank@2314 | 29 | #include "memory/allocation.hpp" |
stefank@2314 | 30 | |
ysr@1876 | 31 | // Forward declarations |
ysr@1876 | 32 | class CompactibleFreeListSpace; |
ysr@1876 | 33 | |
ysr@1876 | 34 | class PromotedObject VALUE_OBJ_CLASS_SPEC { |
ysr@1876 | 35 | private: |
ysr@1876 | 36 | enum { |
ysr@1876 | 37 | promoted_mask = right_n_bits(2), // i.e. 0x3 |
ysr@1876 | 38 | displaced_mark = nth_bit(2), // i.e. 0x4 |
ysr@1876 | 39 | next_mask = ~(right_n_bits(3)) // i.e. ~(0x7) |
ysr@1876 | 40 | }; |
ysr@1901 | 41 | |
ysr@1901 | 42 | // Below, we want _narrow_next in the "higher" 32 bit slot, |
ysr@1901 | 43 | // whose position will depend on endian-ness of the platform. |
ysr@1901 | 44 | // This is so that there is no interference with the |
ysr@1901 | 45 | // cms_free_bit occupying bit position 7 (lsb == 0) |
jmasa@3732 | 46 | // when we are using compressed oops; see FreeChunk::is_free(). |
ysr@1901 | 47 | // We cannot move the cms_free_bit down because currently |
ysr@1901 | 48 | // biased locking code assumes that age bits are contiguous |
ysr@1901 | 49 | // with the lock bits. Even if that assumption were relaxed, |
ysr@1901 | 50 | // the least position we could move this bit to would be |
ysr@1901 | 51 | // to bit position 3, which would require 16 byte alignment. |
ysr@1901 | 52 | typedef struct { |
ysr@1901 | 53 | #ifdef VM_LITTLE_ENDIAN |
ysr@1901 | 54 | LP64_ONLY(narrowOop _pad;) |
ysr@1901 | 55 | narrowOop _narrow_next; |
ysr@1901 | 56 | #else |
ysr@1901 | 57 | narrowOop _narrow_next; |
ysr@1901 | 58 | LP64_ONLY(narrowOop _pad;) |
ysr@1901 | 59 | #endif |
ysr@1901 | 60 | } Data; |
ysr@1901 | 61 | |
ysr@1901 | 62 | union { |
ysr@1901 | 63 | intptr_t _next; |
ysr@1901 | 64 | Data _data; |
ysr@1901 | 65 | }; |
ysr@1876 | 66 | public: |
ysr@1876 | 67 | inline PromotedObject* next() const { |
jmasa@3732 | 68 | assert(!((FreeChunk*)this)->is_free(), "Error"); |
ysr@1901 | 69 | PromotedObject* res; |
ysr@1901 | 70 | if (UseCompressedOops) { |
ysr@1901 | 71 | // The next pointer is a compressed oop stored in the top 32 bits |
ysr@1901 | 72 | res = (PromotedObject*)oopDesc::decode_heap_oop(_data._narrow_next); |
ysr@1901 | 73 | } else { |
ysr@1901 | 74 | res = (PromotedObject*)(_next & next_mask); |
ysr@1901 | 75 | } |
ysr@1901 | 76 | assert(oop(res)->is_oop_or_null(true /* ignore mark word */), "Not an oop?"); |
ysr@1901 | 77 | return res; |
ysr@1876 | 78 | } |
ysr@1876 | 79 | inline void setNext(PromotedObject* x) { |
ysr@1901 | 80 | assert(((intptr_t)x & ~next_mask) == 0, "Conflict in bit usage, " |
ysr@1901 | 81 | "or insufficient alignment of objects"); |
ysr@1901 | 82 | if (UseCompressedOops) { |
ysr@1901 | 83 | assert(_data._narrow_next == 0, "Overwrite?"); |
ysr@1901 | 84 | _data._narrow_next = oopDesc::encode_heap_oop(oop(x)); |
ysr@1901 | 85 | } else { |
ysr@1901 | 86 | _next |= (intptr_t)x; |
ysr@1901 | 87 | } |
jmasa@3732 | 88 | assert(!((FreeChunk*)this)->is_free(), "Error"); |
ysr@1876 | 89 | } |
ysr@1876 | 90 | inline void setPromotedMark() { |
ysr@1876 | 91 | _next |= promoted_mask; |
jmasa@3732 | 92 | assert(!((FreeChunk*)this)->is_free(), "Error"); |
ysr@1876 | 93 | } |
ysr@1876 | 94 | inline bool hasPromotedMark() const { |
jmasa@3732 | 95 | assert(!((FreeChunk*)this)->is_free(), "Error"); |
ysr@1876 | 96 | return (_next & promoted_mask) == promoted_mask; |
ysr@1876 | 97 | } |
ysr@1876 | 98 | inline void setDisplacedMark() { |
ysr@1876 | 99 | _next |= displaced_mark; |
jmasa@3732 | 100 | assert(!((FreeChunk*)this)->is_free(), "Error"); |
ysr@1876 | 101 | } |
ysr@1876 | 102 | inline bool hasDisplacedMark() const { |
jmasa@3732 | 103 | assert(!((FreeChunk*)this)->is_free(), "Error"); |
ysr@1876 | 104 | return (_next & displaced_mark) != 0; |
ysr@1876 | 105 | } |
jmasa@3732 | 106 | inline void clear_next() { |
ysr@1901 | 107 | _next = 0; |
jmasa@3732 | 108 | assert(!((FreeChunk*)this)->is_free(), "Error"); |
ysr@1901 | 109 | } |
ysr@1876 | 110 | debug_only(void *next_addr() { return (void *) &_next; }) |
ysr@1876 | 111 | }; |
ysr@1876 | 112 | |
ysr@1876 | 113 | class SpoolBlock: public FreeChunk { |
ysr@1876 | 114 | friend class PromotionInfo; |
ysr@1876 | 115 | protected: |
ysr@1876 | 116 | SpoolBlock* nextSpoolBlock; |
ysr@1876 | 117 | size_t bufferSize; // number of usable words in this block |
ysr@1876 | 118 | markOop* displacedHdr; // the displaced headers start here |
ysr@1876 | 119 | |
ysr@1876 | 120 | // Note about bufferSize: it denotes the number of entries available plus 1; |
ysr@1876 | 121 | // legal indices range from 1 through BufferSize - 1. See the verification |
ysr@1876 | 122 | // code verify() that counts the number of displaced headers spooled. |
ysr@1876 | 123 | size_t computeBufferSize() { |
ysr@1876 | 124 | return (size() * sizeof(HeapWord) - sizeof(*this)) / sizeof(markOop); |
ysr@1876 | 125 | } |
ysr@1876 | 126 | |
ysr@1876 | 127 | public: |
ysr@1876 | 128 | void init() { |
ysr@1876 | 129 | bufferSize = computeBufferSize(); |
ysr@1876 | 130 | displacedHdr = (markOop*)&displacedHdr; |
ysr@1876 | 131 | nextSpoolBlock = NULL; |
ysr@1876 | 132 | } |
ysr@1876 | 133 | |
ysr@1876 | 134 | void print_on(outputStream* st) const; |
ysr@1876 | 135 | void print() const { print_on(gclog_or_tty); } |
ysr@1876 | 136 | }; |
ysr@1876 | 137 | |
ysr@1876 | 138 | class PromotionInfo VALUE_OBJ_CLASS_SPEC { |
ysr@1876 | 139 | bool _tracking; // set if tracking |
ysr@1876 | 140 | CompactibleFreeListSpace* _space; // the space to which this belongs |
ysr@1876 | 141 | PromotedObject* _promoHead; // head of list of promoted objects |
ysr@1876 | 142 | PromotedObject* _promoTail; // tail of list of promoted objects |
ysr@1876 | 143 | SpoolBlock* _spoolHead; // first spooling block |
ysr@1876 | 144 | SpoolBlock* _spoolTail; // last non-full spooling block or null |
ysr@1876 | 145 | SpoolBlock* _splice_point; // when _spoolTail is null, holds list tail |
ysr@1876 | 146 | SpoolBlock* _spareSpool; // free spool buffer |
ysr@1876 | 147 | size_t _firstIndex; // first active index in |
ysr@1876 | 148 | // first spooling block (_spoolHead) |
ysr@1876 | 149 | size_t _nextIndex; // last active index + 1 in last |
ysr@1876 | 150 | // spooling block (_spoolTail) |
ysr@1876 | 151 | private: |
ysr@1876 | 152 | // ensure that spooling space exists; return true if there is spooling space |
ysr@1876 | 153 | bool ensure_spooling_space_work(); |
ysr@1876 | 154 | |
ysr@1876 | 155 | public: |
ysr@1876 | 156 | PromotionInfo() : |
ysr@1876 | 157 | _tracking(0), _space(NULL), |
ysr@1876 | 158 | _promoHead(NULL), _promoTail(NULL), |
ysr@1876 | 159 | _spoolHead(NULL), _spoolTail(NULL), |
ysr@1876 | 160 | _spareSpool(NULL), _firstIndex(1), |
ysr@1876 | 161 | _nextIndex(1) {} |
ysr@1876 | 162 | |
ysr@1876 | 163 | bool noPromotions() const { |
ysr@1876 | 164 | assert(_promoHead != NULL || _promoTail == NULL, "list inconsistency"); |
ysr@1876 | 165 | return _promoHead == NULL; |
ysr@1876 | 166 | } |
ysr@1876 | 167 | void startTrackingPromotions(); |
ysr@1876 | 168 | void stopTrackingPromotions(uint worker_id = 0); |
ysr@1876 | 169 | bool tracking() const { return _tracking; } |
ysr@1876 | 170 | void track(PromotedObject* trackOop); // keep track of a promoted oop |
ysr@1876 | 171 | // The following variant must be used when trackOop is not fully |
ysr@1876 | 172 | // initialized and has a NULL klass: |
coleenp@4037 | 173 | void track(PromotedObject* trackOop, Klass* klassOfOop); // keep track of a promoted oop |
ysr@1876 | 174 | void setSpace(CompactibleFreeListSpace* sp) { _space = sp; } |
ysr@1876 | 175 | CompactibleFreeListSpace* space() const { return _space; } |
ysr@1876 | 176 | markOop nextDisplacedHeader(); // get next header & forward spool pointer |
ysr@1876 | 177 | void saveDisplacedHeader(markOop hdr); |
ysr@1876 | 178 | // save header and forward spool |
ysr@1876 | 179 | |
ysr@1876 | 180 | inline size_t refillSize() const; |
ysr@1876 | 181 | |
ysr@1876 | 182 | SpoolBlock* getSpoolBlock(); // return a free spooling block |
ysr@1876 | 183 | inline bool has_spooling_space() { |
ysr@1876 | 184 | return _spoolTail != NULL && _spoolTail->bufferSize > _nextIndex; |
ysr@1876 | 185 | } |
ysr@1876 | 186 | // ensure that spooling space exists |
ysr@1876 | 187 | bool ensure_spooling_space() { |
ysr@1876 | 188 | return has_spooling_space() || ensure_spooling_space_work(); |
ysr@1876 | 189 | } |
ysr@1876 | 190 | #define PROMOTED_OOPS_ITERATE_DECL(OopClosureType, nv_suffix) \ |
ysr@1876 | 191 | void promoted_oops_iterate##nv_suffix(OopClosureType* cl); |
ysr@1876 | 192 | ALL_SINCE_SAVE_MARKS_CLOSURES(PROMOTED_OOPS_ITERATE_DECL) |
ysr@1876 | 193 | #undef PROMOTED_OOPS_ITERATE_DECL |
ysr@1876 | 194 | void promoted_oops_iterate(OopsInGenClosure* cl) { |
ysr@1876 | 195 | promoted_oops_iterate_v(cl); |
ysr@1876 | 196 | } |
ysr@1876 | 197 | void verify() const; |
ysr@1876 | 198 | void reset() { |
ysr@1876 | 199 | _promoHead = NULL; |
ysr@1876 | 200 | _promoTail = NULL; |
ysr@1876 | 201 | _spoolHead = NULL; |
ysr@1876 | 202 | _spoolTail = NULL; |
ysr@1876 | 203 | _spareSpool = NULL; |
ysr@1876 | 204 | _firstIndex = 0; |
ysr@1876 | 205 | _nextIndex = 0; |
ysr@1876 | 206 | |
ysr@1876 | 207 | } |
ysr@1876 | 208 | |
ysr@1876 | 209 | void print_on(outputStream* st) const; |
ysr@1876 | 210 | void print_statistics(uint worker_id) const; |
ysr@1876 | 211 | }; |
ysr@1876 | 212 | |
stefank@2314 | 213 | |
stefank@2314 | 214 | #endif // SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_PROMOTIONINFO_HPP |