1441N/A/*
1472N/A * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
1441N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1441N/A *
1441N/A * This code is free software; you can redistribute it and/or modify it
1441N/A * under the terms of the GNU General Public License version 2 only, as
1441N/A * published by the Free Software Foundation.
1441N/A *
1441N/A * This code is distributed in the hope that it will be useful, but WITHOUT
1441N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1441N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1441N/A * version 2 for more details (a copy is included in the LICENSE file that
1441N/A * accompanied this code).
1441N/A *
1441N/A * You should have received a copy of the GNU General Public License version
1441N/A * 2 along with this work; if not, write to the Free Software Foundation,
1441N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1441N/A *
1472N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1472N/A * or visit www.oracle.com if you need additional information or have any
1472N/A * questions.
1441N/A *
1441N/A */
1441N/A
1879N/A#ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_PROMOTIONINFO_HPP
1879N/A#define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_PROMOTIONINFO_HPP
1879N/A
1879N/A#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp"
1879N/A#include "memory/allocation.hpp"
1879N/A
1441N/A// Forward declarations
1441N/Aclass CompactibleFreeListSpace;
1441N/A
1441N/Aclass PromotedObject VALUE_OBJ_CLASS_SPEC {
1441N/A private:
1441N/A enum {
1441N/A promoted_mask = right_n_bits(2), // i.e. 0x3
1441N/A displaced_mark = nth_bit(2), // i.e. 0x4
1441N/A next_mask = ~(right_n_bits(3)) // i.e. ~(0x7)
1441N/A };
1466N/A
1466N/A // Below, we want _narrow_next in the "higher" 32 bit slot,
1466N/A // whose position will depend on endian-ness of the platform.
1466N/A // This is so that there is no interference with the
1466N/A // cms_free_bit occupying bit position 7 (lsb == 0)
3697N/A // when we are using compressed oops; see FreeChunk::is_free().
1466N/A // We cannot move the cms_free_bit down because currently
1466N/A // biased locking code assumes that age bits are contiguous
1466N/A // with the lock bits. Even if that assumption were relaxed,
1466N/A // the least position we could move this bit to would be
1466N/A // to bit position 3, which would require 16 byte alignment.
1466N/A typedef struct {
1466N/A#ifdef VM_LITTLE_ENDIAN
1466N/A LP64_ONLY(narrowOop _pad;)
1466N/A narrowOop _narrow_next;
1466N/A#else
1466N/A narrowOop _narrow_next;
1466N/A LP64_ONLY(narrowOop _pad;)
1466N/A#endif
1466N/A } Data;
1466N/A
1466N/A union {
1466N/A intptr_t _next;
1466N/A Data _data;
1466N/A };
1441N/A public:
1441N/A inline PromotedObject* next() const {
3697N/A assert(!((FreeChunk*)this)->is_free(), "Error");
1466N/A PromotedObject* res;
1466N/A if (UseCompressedOops) {
1466N/A // The next pointer is a compressed oop stored in the top 32 bits
1466N/A res = (PromotedObject*)oopDesc::decode_heap_oop(_data._narrow_next);
1466N/A } else {
1466N/A res = (PromotedObject*)(_next & next_mask);
1466N/A }
1466N/A assert(oop(res)->is_oop_or_null(true /* ignore mark word */), "Not an oop?");
1466N/A return res;
1441N/A }
1441N/A inline void setNext(PromotedObject* x) {
1466N/A assert(((intptr_t)x & ~next_mask) == 0, "Conflict in bit usage, "
1466N/A "or insufficient alignment of objects");
1466N/A if (UseCompressedOops) {
1466N/A assert(_data._narrow_next == 0, "Overwrite?");
1466N/A _data._narrow_next = oopDesc::encode_heap_oop(oop(x));
1466N/A } else {
1466N/A _next |= (intptr_t)x;
1466N/A }
3697N/A assert(!((FreeChunk*)this)->is_free(), "Error");
1441N/A }
1441N/A inline void setPromotedMark() {
1441N/A _next |= promoted_mask;
3697N/A assert(!((FreeChunk*)this)->is_free(), "Error");
1441N/A }
1441N/A inline bool hasPromotedMark() const {
3697N/A assert(!((FreeChunk*)this)->is_free(), "Error");
1441N/A return (_next & promoted_mask) == promoted_mask;
1441N/A }
1441N/A inline void setDisplacedMark() {
1441N/A _next |= displaced_mark;
3697N/A assert(!((FreeChunk*)this)->is_free(), "Error");
1441N/A }
1441N/A inline bool hasDisplacedMark() const {
3697N/A assert(!((FreeChunk*)this)->is_free(), "Error");
1441N/A return (_next & displaced_mark) != 0;
1441N/A }
3697N/A inline void clear_next() {
1466N/A _next = 0;
3697N/A assert(!((FreeChunk*)this)->is_free(), "Error");
1466N/A }
1441N/A debug_only(void *next_addr() { return (void *) &_next; })
1441N/A};
1441N/A
1441N/Aclass SpoolBlock: public FreeChunk {
1441N/A friend class PromotionInfo;
1441N/A protected:
1441N/A SpoolBlock* nextSpoolBlock;
1441N/A size_t bufferSize; // number of usable words in this block
1441N/A markOop* displacedHdr; // the displaced headers start here
1441N/A
1441N/A // Note about bufferSize: it denotes the number of entries available plus 1;
1441N/A // legal indices range from 1 through BufferSize - 1. See the verification
1441N/A // code verify() that counts the number of displaced headers spooled.
1441N/A size_t computeBufferSize() {
1441N/A return (size() * sizeof(HeapWord) - sizeof(*this)) / sizeof(markOop);
1441N/A }
1441N/A
1441N/A public:
1441N/A void init() {
1441N/A bufferSize = computeBufferSize();
1441N/A displacedHdr = (markOop*)&displacedHdr;
1441N/A nextSpoolBlock = NULL;
1441N/A }
1441N/A
1441N/A void print_on(outputStream* st) const;
1441N/A void print() const { print_on(gclog_or_tty); }
1441N/A};
1441N/A
1441N/Aclass PromotionInfo VALUE_OBJ_CLASS_SPEC {
1441N/A bool _tracking; // set if tracking
1441N/A CompactibleFreeListSpace* _space; // the space to which this belongs
1441N/A PromotedObject* _promoHead; // head of list of promoted objects
1441N/A PromotedObject* _promoTail; // tail of list of promoted objects
1441N/A SpoolBlock* _spoolHead; // first spooling block
1441N/A SpoolBlock* _spoolTail; // last non-full spooling block or null
1441N/A SpoolBlock* _splice_point; // when _spoolTail is null, holds list tail
1441N/A SpoolBlock* _spareSpool; // free spool buffer
1441N/A size_t _firstIndex; // first active index in
1441N/A // first spooling block (_spoolHead)
1441N/A size_t _nextIndex; // last active index + 1 in last
1441N/A // spooling block (_spoolTail)
1441N/A private:
1441N/A // ensure that spooling space exists; return true if there is spooling space
1441N/A bool ensure_spooling_space_work();
1441N/A
1441N/A public:
1441N/A PromotionInfo() :
1441N/A _tracking(0), _space(NULL),
1441N/A _promoHead(NULL), _promoTail(NULL),
1441N/A _spoolHead(NULL), _spoolTail(NULL),
1441N/A _spareSpool(NULL), _firstIndex(1),
1441N/A _nextIndex(1) {}
1441N/A
1441N/A bool noPromotions() const {
1441N/A assert(_promoHead != NULL || _promoTail == NULL, "list inconsistency");
1441N/A return _promoHead == NULL;
1441N/A }
1441N/A void startTrackingPromotions();
1441N/A void stopTrackingPromotions(uint worker_id = 0);
1441N/A bool tracking() const { return _tracking; }
1441N/A void track(PromotedObject* trackOop); // keep track of a promoted oop
1441N/A // The following variant must be used when trackOop is not fully
1441N/A // initialized and has a NULL klass:
1441N/A void track(PromotedObject* trackOop, klassOop klassOfOop); // keep track of a promoted oop
1441N/A void setSpace(CompactibleFreeListSpace* sp) { _space = sp; }
1441N/A CompactibleFreeListSpace* space() const { return _space; }
1441N/A markOop nextDisplacedHeader(); // get next header & forward spool pointer
1441N/A void saveDisplacedHeader(markOop hdr);
1441N/A // save header and forward spool
1441N/A
1441N/A inline size_t refillSize() const;
1441N/A
1441N/A SpoolBlock* getSpoolBlock(); // return a free spooling block
1441N/A inline bool has_spooling_space() {
1441N/A return _spoolTail != NULL && _spoolTail->bufferSize > _nextIndex;
1441N/A }
1441N/A // ensure that spooling space exists
1441N/A bool ensure_spooling_space() {
1441N/A return has_spooling_space() || ensure_spooling_space_work();
1441N/A }
1441N/A #define PROMOTED_OOPS_ITERATE_DECL(OopClosureType, nv_suffix) \
1441N/A void promoted_oops_iterate##nv_suffix(OopClosureType* cl);
1441N/A ALL_SINCE_SAVE_MARKS_CLOSURES(PROMOTED_OOPS_ITERATE_DECL)
1441N/A #undef PROMOTED_OOPS_ITERATE_DECL
1441N/A void promoted_oops_iterate(OopsInGenClosure* cl) {
1441N/A promoted_oops_iterate_v(cl);
1441N/A }
1441N/A void verify() const;
1441N/A void reset() {
1441N/A _promoHead = NULL;
1441N/A _promoTail = NULL;
1441N/A _spoolHead = NULL;
1441N/A _spoolTail = NULL;
1441N/A _spareSpool = NULL;
1441N/A _firstIndex = 0;
1441N/A _nextIndex = 0;
1441N/A
1441N/A }
1441N/A
1441N/A void print_on(outputStream* st) const;
1441N/A void print_statistics(uint worker_id) const;
1441N/A};
1441N/A
1879N/A
1879N/A#endif // SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_PROMOTIONINFO_HPP