view src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.hpp @ 10185:d50cc62e94ff

8012715: G1: GraphKit accesses PtrQueue::_index as int but is size_t Summary: In graphKit INT operations were generated to access PtrQueue::_index which has type size_t. This is 64 bit on 64-bit machines. No problems occur on little endian machines as long as the index fits into 32 bit, but on big endian machines the upper part is read, which is zero. This leads to unnecessary branches to the slow path in the runtime. Reviewed-by: twisti, johnc Contributed-by: Martin Doerr <martin.doerr@sap.com>
author johnc
date Wed, 24 Apr 2013 14:48:43 -0700
parents da91efe96a93
children
line wrap: on
line source

/*
 * Copyright (c) 2010, 2012, 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.
 *
 */

#ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_PROMOTIONINFO_HPP
#define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_PROMOTIONINFO_HPP

#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp"
#include "memory/allocation.hpp"

// Forward declarations
class CompactibleFreeListSpace;

class PromotedObject VALUE_OBJ_CLASS_SPEC {
 private:
  enum {
    promoted_mask  = right_n_bits(2),   // i.e. 0x3
    displaced_mark = nth_bit(2),        // i.e. 0x4
    next_mask      = ~(right_n_bits(3)) // i.e. ~(0x7)
  };

  // Below, we want _narrow_next in the "higher" 32 bit slot,
  // whose position will depend on endian-ness of the platform.
  // This is so that there is no interference with the
  // cms_free_bit occupying bit position 7 (lsb == 0)
  // when we are using compressed oops; see FreeChunk::is_free().
  // We cannot move the cms_free_bit down because currently
  // biased locking code assumes that age bits are contiguous
  // with the lock bits. Even if that assumption were relaxed,
  // the least position we could move this bit to would be
  // to bit position 3, which would require 16 byte alignment.
  typedef struct {
#ifdef VM_LITTLE_ENDIAN
    LP64_ONLY(narrowOop _pad;)
              narrowOop _narrow_next;
#else
              narrowOop _narrow_next;
    LP64_ONLY(narrowOop _pad;)
#endif
  } Data;

  union {
    intptr_t _next;
    Data     _data;
  };
 public:
  inline PromotedObject* next() const {
    assert(!((FreeChunk*)this)->is_free(), "Error");
    PromotedObject* res;
    if (UseCompressedOops) {
      // The next pointer is a compressed oop stored in the top 32 bits
      res = (PromotedObject*)oopDesc::decode_heap_oop(_data._narrow_next);
    } else {
      res = (PromotedObject*)(_next & next_mask);
    }
    assert(oop(res)->is_oop_or_null(true /* ignore mark word */), "Not an oop?");
    return res;
  }
  inline void setNext(PromotedObject* x) {
    assert(((intptr_t)x & ~next_mask) == 0, "Conflict in bit usage, "
           "or insufficient alignment of objects");
    if (UseCompressedOops) {
      assert(_data._narrow_next == 0, "Overwrite?");
      _data._narrow_next = oopDesc::encode_heap_oop(oop(x));
    } else {
      _next |= (intptr_t)x;
    }
    assert(!((FreeChunk*)this)->is_free(), "Error");
  }
  inline void setPromotedMark() {
    _next |= promoted_mask;
    assert(!((FreeChunk*)this)->is_free(), "Error");
  }
  inline bool hasPromotedMark() const {
    assert(!((FreeChunk*)this)->is_free(), "Error");
    return (_next & promoted_mask) == promoted_mask;
  }
  inline void setDisplacedMark() {
    _next |= displaced_mark;
    assert(!((FreeChunk*)this)->is_free(), "Error");
  }
  inline bool hasDisplacedMark() const {
    assert(!((FreeChunk*)this)->is_free(), "Error");
    return (_next & displaced_mark) != 0;
  }
  inline void clear_next()        {
    _next = 0;
    assert(!((FreeChunk*)this)->is_free(), "Error");
  }
  debug_only(void *next_addr() { return (void *) &_next; })
};

class SpoolBlock: public FreeChunk {
  friend class PromotionInfo;
 protected:
  SpoolBlock*  nextSpoolBlock;
  size_t       bufferSize;        // number of usable words in this block
  markOop*     displacedHdr;      // the displaced headers start here

  // Note about bufferSize: it denotes the number of entries available plus 1;
  // legal indices range from 1 through BufferSize - 1.  See the verification
  // code verify() that counts the number of displaced headers spooled.
  size_t computeBufferSize() {
    return (size() * sizeof(HeapWord) - sizeof(*this)) / sizeof(markOop);
  }

 public:
  void init() {
    bufferSize = computeBufferSize();
    displacedHdr = (markOop*)&displacedHdr;
    nextSpoolBlock = NULL;
  }

  void print_on(outputStream* st) const;
  void print() const { print_on(gclog_or_tty); }
};

class PromotionInfo VALUE_OBJ_CLASS_SPEC {
  bool            _tracking;      // set if tracking
  CompactibleFreeListSpace* _space; // the space to which this belongs
  PromotedObject* _promoHead;     // head of list of promoted objects
  PromotedObject* _promoTail;     // tail of list of promoted objects
  SpoolBlock*     _spoolHead;     // first spooling block
  SpoolBlock*     _spoolTail;     // last  non-full spooling block or null
  SpoolBlock*     _splice_point;  // when _spoolTail is null, holds list tail
  SpoolBlock*     _spareSpool;    // free spool buffer
  size_t          _firstIndex;    // first active index in
                                  // first spooling block (_spoolHead)
  size_t          _nextIndex;     // last active index + 1 in last
                                  // spooling block (_spoolTail)
 private:
  // ensure that spooling space exists; return true if there is spooling space
  bool ensure_spooling_space_work();

 public:
  PromotionInfo() :
    _tracking(0), _space(NULL),
    _promoHead(NULL), _promoTail(NULL),
    _spoolHead(NULL), _spoolTail(NULL),
    _spareSpool(NULL), _firstIndex(1),
    _nextIndex(1) {}

  bool noPromotions() const {
    assert(_promoHead != NULL || _promoTail == NULL, "list inconsistency");
    return _promoHead == NULL;
  }
  void startTrackingPromotions();
  void stopTrackingPromotions(uint worker_id = 0);
  bool tracking() const          { return _tracking;  }
  void track(PromotedObject* trackOop);      // keep track of a promoted oop
  // The following variant must be used when trackOop is not fully
  // initialized and has a NULL klass:
  void track(PromotedObject* trackOop, Klass* klassOfOop); // keep track of a promoted oop
  void setSpace(CompactibleFreeListSpace* sp) { _space = sp; }
  CompactibleFreeListSpace* space() const     { return _space; }
  markOop nextDisplacedHeader(); // get next header & forward spool pointer
  void    saveDisplacedHeader(markOop hdr);
                                 // save header and forward spool

  inline size_t refillSize() const;

  SpoolBlock* getSpoolBlock();   // return a free spooling block
  inline bool has_spooling_space() {
    return _spoolTail != NULL && _spoolTail->bufferSize > _nextIndex;
  }
  // ensure that spooling space exists
  bool ensure_spooling_space() {
    return has_spooling_space() || ensure_spooling_space_work();
  }
  #define PROMOTED_OOPS_ITERATE_DECL(OopClosureType, nv_suffix)  \
    void promoted_oops_iterate##nv_suffix(OopClosureType* cl);
  ALL_SINCE_SAVE_MARKS_CLOSURES(PROMOTED_OOPS_ITERATE_DECL)
  #undef PROMOTED_OOPS_ITERATE_DECL
  void promoted_oops_iterate(OopsInGenClosure* cl) {
    promoted_oops_iterate_v(cl);
  }
  void verify()  const;
  void reset() {
    _promoHead = NULL;
    _promoTail = NULL;
    _spoolHead = NULL;
    _spoolTail = NULL;
    _spareSpool = NULL;
    _firstIndex = 0;
    _nextIndex = 0;

  }

  void print_on(outputStream* st) const;
  void print_statistics(uint worker_id) const;
};


#endif // SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_PROMOTIONINFO_HPP