6687581: Make CMS work with compressed oops

Mon, 09 Jun 2008 11:51:19 -0400

author
coleenp
date
Mon, 09 Jun 2008 11:51:19 -0400
changeset 622
790e66e5fbac
parent 620
8759d37f2524
child 623
c0ecab83e6f3

6687581: Make CMS work with compressed oops
Summary: Make FreeChunk read markword instead of LSB in _klass pointer to indicate that it's a FreeChunk for compressed oops.
Reviewed-by: ysr, jmasa

agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java file | annotate | diff | comparison | revisions
agent/src/share/classes/sun/jvm/hotspot/memory/FreeChunk.java file | annotate | diff | comparison | revisions
agent/src/share/classes/sun/jvm/hotspot/oops/Mark.java file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep file | annotate | diff | comparison | revisions
src/share/vm/oops/markOop.hpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/arguments.cpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/vmStructs.cpp file | annotate | diff | comparison | revisions
     1.1 --- a/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java	Fri Jun 06 11:47:26 2008 -0700
     1.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java	Mon Jun 09 11:51:19 2008 -0400
     1.3 @@ -121,7 +121,7 @@
     1.4              cur = cur.addOffsetTo(adjustObjectSizeInBytes(size));
     1.5           }
     1.6  
     1.7 -         if (FreeChunk.secondWordIndicatesFreeChunk(dbg.getAddressValue(klassOop))) {
     1.8 +         if (FreeChunk.indicatesFreeChunk(cur)) {
     1.9              if (! cur.equals(regionStart)) {
    1.10                 res.add(new MemRegion(regionStart, cur));
    1.11              }
     2.1 --- a/agent/src/share/classes/sun/jvm/hotspot/memory/FreeChunk.java	Fri Jun 06 11:47:26 2008 -0700
     2.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/FreeChunk.java	Mon Jun 09 11:51:19 2008 -0400
     2.3 @@ -28,6 +28,7 @@
     2.4  import sun.jvm.hotspot.debugger.*;
     2.5  import sun.jvm.hotspot.types.*;
     2.6  import sun.jvm.hotspot.runtime.*;
     2.7 +import sun.jvm.hotspot.oops.*;
     2.8  
     2.9  public class FreeChunk extends VMObject {
    2.10     static {
    2.11 @@ -42,13 +43,13 @@
    2.12        Type type = db.lookupType("FreeChunk");
    2.13        nextField = type.getAddressField("_next");
    2.14        prevField = type.getAddressField("_prev");
    2.15 -      sizeField = type.getCIntegerField("_size");
    2.16 +      sizeField = type.getAddressField("_size");
    2.17     }
    2.18  
    2.19     // Fields
    2.20     private static AddressField nextField;
    2.21     private static AddressField prevField;
    2.22 -   private static CIntegerField sizeField;
    2.23 +   private static AddressField sizeField;
    2.24  
    2.25     // Accessors
    2.26     public FreeChunk next() {
    2.27 @@ -61,20 +62,34 @@
    2.28     }
    2.29  
    2.30     public long size() {
    2.31 -      return sizeField.getValue(addr);
    2.32 +      if (VM.getVM().isCompressedOopsEnabled()) {
    2.33 +        Mark mark = new Mark(sizeField.getValue(addr));
    2.34 +        return mark.getSize();
    2.35 +      } else {
    2.36 +        Address size = sizeField.getValue(addr);
    2.37 +        Debugger dbg = VM.getVM().getDebugger();
    2.38 +        return dbg.getAddressValue(size);
    2.39 +      }
    2.40     }
    2.41  
    2.42     public FreeChunk(Address addr) {
    2.43        super(addr);
    2.44     }
    2.45  
    2.46 -   public static boolean secondWordIndicatesFreeChunk(long word) {
    2.47 -      return (word & 0x1L) == 0x1L;
    2.48 +   public static boolean indicatesFreeChunk(Address cur) {
    2.49 +      FreeChunk f = new FreeChunk(cur);
    2.50 +      return f.isFree();
    2.51     }
    2.52  
    2.53     public boolean isFree() {
    2.54 -      Debugger dbg = VM.getVM().getDebugger();
    2.55 -      Address prev = prevField.getValue(addr);
    2.56 -      return secondWordIndicatesFreeChunk(dbg.getAddressValue(prev));
    2.57 +      if (VM.getVM().isCompressedOopsEnabled()) {
    2.58 +        Mark mark = new Mark(sizeField.getValue(addr));
    2.59 +        return mark.isCmsFreeChunk();
    2.60 +      } else {
    2.61 +        Address prev = prevField.getValue(addr);
    2.62 +        Debugger dbg = VM.getVM().getDebugger();
    2.63 +        long word = dbg.getAddressValue(prev);
    2.64 +        return (word & 0x1L) == 0x1L;
    2.65 +      }
    2.66     }
    2.67  }
     3.1 --- a/agent/src/share/classes/sun/jvm/hotspot/oops/Mark.java	Fri Jun 06 11:47:26 2008 -0700
     3.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Mark.java	Mon Jun 09 11:51:19 2008 -0400
     3.3 @@ -79,6 +79,11 @@
     3.4      noHashInPlace       = db.lookupLongConstant("markOopDesc::no_hash_in_place").longValue();
     3.5      noLockInPlace       = db.lookupLongConstant("markOopDesc::no_lock_in_place").longValue();
     3.6      maxAge              = db.lookupLongConstant("markOopDesc::max_age").longValue();
     3.7 +
     3.8 +    /* Constants in markOop used by CMS. */
     3.9 +    cmsShift            = db.lookupLongConstant("markOopDesc::cms_shift").longValue();
    3.10 +    cmsMask             = db.lookupLongConstant("markOopDesc::cms_mask").longValue();
    3.11 +    sizeShift           = db.lookupLongConstant("markOopDesc::size_shift").longValue();
    3.12    }
    3.13  
    3.14    // Field accessors
    3.15 @@ -120,6 +125,11 @@
    3.16  
    3.17    private static long maxAge;
    3.18  
    3.19 +  /* Constants in markOop used by CMS. */
    3.20 +  private static long cmsShift;
    3.21 +  private static long cmsMask;
    3.22 +  private static long sizeShift;
    3.23 +
    3.24    public Mark(Address addr) {
    3.25      super(addr);
    3.26    }
    3.27 @@ -290,4 +300,11 @@
    3.28    //
    3.29    //  // Recover address of oop from encoded form used in mark
    3.30    //  inline void* decode_pointer() { return clear_lock_bits(); }
    3.31 +
    3.32 +  // Copy markOop methods for CMS here.
    3.33 +  public boolean isCmsFreeChunk() {
    3.34 +    return isUnlocked() &&
    3.35 +           (Bits.maskBitsLong(value() >> cmsShift, cmsMask) & 0x1L) == 0x1L;
    3.36 +  }
    3.37 +  public long getSize() { return (long)(value() >> sizeShift); }
    3.38  }
     4.1 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp	Fri Jun 06 11:47:26 2008 -0700
     4.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp	Mon Jun 09 11:51:19 2008 -0400
     4.3 @@ -805,28 +805,30 @@
     4.4    // This must be volatile, or else there is a danger that the compiler
     4.5    // will compile the code below into a sometimes-infinite loop, by keeping
     4.6    // the value read the first time in a register.
     4.7 -  oop o = (oop)p;
     4.8 -  volatile oop* second_word_addr = o->klass_addr();
     4.9    while (true) {
    4.10 -    klassOop k = (klassOop)(*second_word_addr);
    4.11      // We must do this until we get a consistent view of the object.
    4.12 -    if (FreeChunk::secondWordIndicatesFreeChunk((intptr_t)k)) {
    4.13 -      FreeChunk* fc = (FreeChunk*)p;
    4.14 -      volatile size_t* sz_addr = (volatile size_t*)(fc->size_addr());
    4.15 -      size_t res = (*sz_addr);
    4.16 -      klassOop k2 = (klassOop)(*second_word_addr);  // Read to confirm.
    4.17 -      if (k == k2) {
    4.18 +    if (FreeChunk::indicatesFreeChunk(p)) {
    4.19 +      volatile FreeChunk* fc = (volatile FreeChunk*)p;
    4.20 +      size_t res = fc->size();
    4.21 +      // If the object is still a free chunk, return the size, else it
    4.22 +      // has been allocated so try again.
    4.23 +      if (FreeChunk::indicatesFreeChunk(p)) {
    4.24          assert(res != 0, "Block size should not be 0");
    4.25          return res;
    4.26        }
    4.27 -    } else if (k != NULL) {
    4.28 -      assert(k->is_oop(true /* ignore mark word */), "Should really be klass oop.");
    4.29 -      assert(o->is_parsable(), "Should be parsable");
    4.30 -      assert(o->is_oop(true /* ignore mark word */), "Should be an oop.");
    4.31 -      size_t res = o->size_given_klass(k->klass_part());
    4.32 -      res = adjustObjectSize(res);
    4.33 -      assert(res != 0, "Block size should not be 0");
    4.34 -      return res;
    4.35 +    } else {
    4.36 +      // must read from what 'p' points to in each loop.
    4.37 +      klassOop k = ((volatile oopDesc*)p)->klass_or_null();
    4.38 +      if (k != NULL) {
    4.39 +        assert(k->is_oop(true /* ignore mark word */), "Should really be klass oop.");
    4.40 +        oop o = (oop)p;
    4.41 +        assert(o->is_parsable(), "Should be parsable");
    4.42 +        assert(o->is_oop(true /* ignore mark word */), "Should be an oop.");
    4.43 +        size_t res = o->size_given_klass(k->klass_part());
    4.44 +        res = adjustObjectSize(res);
    4.45 +        assert(res != 0, "Block size should not be 0");
    4.46 +        return res;
    4.47 +      }
    4.48      }
    4.49    }
    4.50  }
    4.51 @@ -845,31 +847,31 @@
    4.52    // This must be volatile, or else there is a danger that the compiler
    4.53    // will compile the code below into a sometimes-infinite loop, by keeping
    4.54    // the value read the first time in a register.
    4.55 -  oop o = (oop)p;
    4.56 -  volatile oop* second_word_addr = o->klass_addr();
    4.57    DEBUG_ONLY(uint loops = 0;)
    4.58    while (true) {
    4.59 -    klassOop k = (klassOop)(*second_word_addr);
    4.60      // We must do this until we get a consistent view of the object.
    4.61 -    if (FreeChunk::secondWordIndicatesFreeChunk((intptr_t)k)) {
    4.62 -      FreeChunk* fc = (FreeChunk*)p;
    4.63 -      volatile size_t* sz_addr = (volatile size_t*)(fc->size_addr());
    4.64 -      size_t res = (*sz_addr);
    4.65 -      klassOop k2 = (klassOop)(*second_word_addr);  // Read to confirm.
    4.66 -      if (k == k2) {
    4.67 +    if (FreeChunk::indicatesFreeChunk(p)) {
    4.68 +      volatile FreeChunk* fc = (volatile FreeChunk*)p;
    4.69 +      size_t res = fc->size();
    4.70 +      if (FreeChunk::indicatesFreeChunk(p)) {
    4.71          assert(res != 0, "Block size should not be 0");
    4.72          assert(loops == 0, "Should be 0");
    4.73          return res;
    4.74        }
    4.75 -    } else if (k != NULL && o->is_parsable()) {
    4.76 -      assert(k->is_oop(), "Should really be klass oop.");
    4.77 -      assert(o->is_oop(), "Should be an oop");
    4.78 -      size_t res = o->size_given_klass(k->klass_part());
    4.79 -      res = adjustObjectSize(res);
    4.80 -      assert(res != 0, "Block size should not be 0");
    4.81 -      return res;
    4.82      } else {
    4.83 -      return c->block_size_if_printezis_bits(p);
    4.84 +      // must read from what 'p' points to in each loop.
    4.85 +      klassOop k = ((volatile oopDesc*)p)->klass_or_null();
    4.86 +      if (k != NULL && ((oopDesc*)p)->is_parsable()) {
    4.87 +        assert(k->is_oop(), "Should really be klass oop.");
    4.88 +        oop o = (oop)p;
    4.89 +        assert(o->is_oop(), "Should be an oop");
    4.90 +        size_t res = o->size_given_klass(k->klass_part());
    4.91 +        res = adjustObjectSize(res);
    4.92 +        assert(res != 0, "Block size should not be 0");
    4.93 +        return res;
    4.94 +      } else {
    4.95 +        return c->block_size_if_printezis_bits(p);
    4.96 +      }
    4.97      }
    4.98      assert(loops == 0, "Can loop at most once");
    4.99      DEBUG_ONLY(loops++;)
   4.100 @@ -907,9 +909,8 @@
   4.101    // and those objects (if garbage) may have been modified to hold
   4.102    // live range information.
   4.103    // assert(ParallelGCThreads > 0 || _bt.block_start(p) == p, "Should be a block boundary");
   4.104 -  klassOop k = oop(p)->klass();
   4.105 -  intptr_t ki = (intptr_t)k;
   4.106 -  if (FreeChunk::secondWordIndicatesFreeChunk(ki)) return false;
   4.107 +  if (FreeChunk::indicatesFreeChunk(p)) return false;
   4.108 +  klassOop k = oop(p)->klass_or_null();
   4.109    if (k != NULL) {
   4.110      // Ignore mark word because it may have been used to
   4.111      // chain together promoted objects (the last one
   4.112 @@ -1027,7 +1028,7 @@
   4.113      FreeChunk* fc = (FreeChunk*)res;
   4.114      fc->markNotFree();
   4.115      assert(!fc->isFree(), "shouldn't be marked free");
   4.116 -    assert(oop(fc)->klass() == NULL, "should look uninitialized");
   4.117 +    assert(oop(fc)->klass_or_null() == NULL, "should look uninitialized");
   4.118      // Verify that the block offset table shows this to
   4.119      // be a single block, but not one which is unallocated.
   4.120      _bt.verify_single_block(res, size);
   4.121 @@ -2593,7 +2594,7 @@
   4.122    }
   4.123    res->markNotFree();
   4.124    assert(!res->isFree(), "shouldn't be marked free");
   4.125 -  assert(oop(res)->klass() == NULL, "should look uninitialized");
   4.126 +  assert(oop(res)->klass_or_null() == NULL, "should look uninitialized");
   4.127    // mangle a just allocated object with a distinct pattern.
   4.128    debug_only(res->mangleAllocated(word_sz));
   4.129    return (HeapWord*)res;
     5.1 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Fri Jun 06 11:47:26 2008 -0700
     5.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Mon Jun 09 11:51:19 2008 -0400
     5.3 @@ -190,7 +190,8 @@
     5.4    // depends on this property.
     5.5    debug_only(
     5.6      FreeChunk* junk = NULL;
     5.7 -    assert(junk->prev_addr() == (void*)(oop(junk)->klass_addr()),
     5.8 +    assert(UseCompressedOops ||
     5.9 +           junk->prev_addr() == (void*)(oop(junk)->klass_addr()),
    5.10             "Offset of FreeChunk::_prev within FreeChunk must match"
    5.11             "  that of OopDesc::_klass within OopDesc");
    5.12    )
    5.13 @@ -1039,7 +1040,7 @@
    5.14                                        // mark end of object
    5.15    }
    5.16    // check that oop looks uninitialized
    5.17 -  assert(oop(start)->klass() == NULL, "_klass should be NULL");
    5.18 +  assert(oop(start)->klass_or_null() == NULL, "_klass should be NULL");
    5.19  }
    5.20  
    5.21  void CMSCollector::promoted(bool par, HeapWord* start,
    5.22 @@ -1309,17 +1310,25 @@
    5.23       }
    5.24    }
    5.25    oop obj = oop(obj_ptr);
    5.26 -  assert(obj->klass() == NULL, "Object should be uninitialized here.");
    5.27 +  assert(obj->klass_or_null() == NULL, "Object should be uninitialized here.");
    5.28    // Otherwise, copy the object.  Here we must be careful to insert the
    5.29    // klass pointer last, since this marks the block as an allocated object.
    5.30 +  // Except with compressed oops it's the mark word.
    5.31    HeapWord* old_ptr = (HeapWord*)old;
    5.32    if (word_sz > (size_t)oopDesc::header_size()) {
    5.33      Copy::aligned_disjoint_words(old_ptr + oopDesc::header_size(),
    5.34                                   obj_ptr + oopDesc::header_size(),
    5.35                                   word_sz - oopDesc::header_size());
    5.36    }
    5.37 +
    5.38 +  if (UseCompressedOops) {
    5.39 +    // Copy gap missed by (aligned) header size calculation above
    5.40 +    obj->set_klass_gap(old->klass_gap());
    5.41 +  }
    5.42 +
    5.43    // Restore the mark word copied above.
    5.44    obj->set_mark(m);
    5.45 +
    5.46    // Now we can track the promoted object, if necessary.  We take care
    5.47    // To delay the transition from uninitialized to full object
    5.48    // (i.e., insertion of klass pointer) until after, so that it
    5.49 @@ -1327,7 +1336,8 @@
    5.50    if (promoInfo->tracking()) {
    5.51      promoInfo->track((PromotedObject*)obj, old->klass());
    5.52    }
    5.53 -  // Finally, install the klass pointer.
    5.54 +
    5.55 +  // Finally, install the klass pointer (this should be volatile).
    5.56    obj->set_klass(old->klass());
    5.57  
    5.58    assert(old->is_oop(), "Will dereference klass ptr below");
    5.59 @@ -6165,7 +6175,7 @@
    5.60  HeapWord* CMSCollector::next_card_start_after_block(HeapWord* addr) const {
    5.61    size_t sz = 0;
    5.62    oop p = (oop)addr;
    5.63 -  if (p->klass() != NULL && p->is_parsable()) {
    5.64 +  if (p->klass_or_null() != NULL && p->is_parsable()) {
    5.65      sz = CompactibleFreeListSpace::adjustObjectSize(p->size());
    5.66    } else {
    5.67      sz = block_size_using_printezis_bits(addr);
    5.68 @@ -6602,7 +6612,7 @@
    5.69    }
    5.70    if (_bitMap->isMarked(addr)) {
    5.71      // it's marked; is it potentially uninitialized?
    5.72 -    if (p->klass() != NULL) {
    5.73 +    if (p->klass_or_null() != NULL) {
    5.74        if (CMSPermGenPrecleaningEnabled && !p->is_parsable()) {
    5.75          // Signal precleaning to redirty the card since
    5.76          // the klass pointer is already installed.
    5.77 @@ -6615,11 +6625,8 @@
    5.78          if (p->is_objArray()) {
    5.79            // objArrays are precisely marked; restrict scanning
    5.80            // to dirty cards only.
    5.81 -          size = p->oop_iterate(_scanningClosure, mr);
    5.82 -          assert(size == CompactibleFreeListSpace::adjustObjectSize(size),
    5.83 -                 "adjustObjectSize should be the identity for array sizes, "
    5.84 -                 "which are necessarily larger than minimum object size of "
    5.85 -                 "two heap words");
    5.86 +          size = CompactibleFreeListSpace::adjustObjectSize(
    5.87 +                   p->oop_iterate(_scanningClosure, mr));
    5.88          } else {
    5.89            // A non-array may have been imprecisely marked; we need
    5.90            // to scan object in its entirety.
    5.91 @@ -6653,7 +6660,7 @@
    5.92      }
    5.93    } else {
    5.94      // Either a not yet marked object or an uninitialized object
    5.95 -    if (p->klass() == NULL || !p->is_parsable()) {
    5.96 +    if (p->klass_or_null() == NULL || !p->is_parsable()) {
    5.97        // An uninitialized object, skip to the next card, since
    5.98        // we may not be able to read its P-bits yet.
    5.99        assert(size == 0, "Initial value");
   5.100 @@ -6710,7 +6717,7 @@
   5.101    HeapWord* addr = (HeapWord*)p;
   5.102    DEBUG_ONLY(_collector->verify_work_stacks_empty();)
   5.103    assert(!_span.contains(addr), "we are scanning the survivor spaces");
   5.104 -  assert(p->klass() != NULL, "object should be initializd");
   5.105 +  assert(p->klass_or_null() != NULL, "object should be initializd");
   5.106    assert(p->is_parsable(), "must be parsable.");
   5.107    // an initialized object; ignore mark word in verification below
   5.108    // since we are running concurrent with mutators
   5.109 @@ -6868,7 +6875,7 @@
   5.110      assert(_skipBits == 0, "tautology");
   5.111      _skipBits = 2;  // skip next two marked bits ("Printezis-marks")
   5.112      oop p = oop(addr);
   5.113 -    if (p->klass() == NULL || !p->is_parsable()) {
   5.114 +    if (p->klass_or_null() == NULL || !p->is_parsable()) {
   5.115        DEBUG_ONLY(if (!_verifying) {)
   5.116          // We re-dirty the cards on which this object lies and increase
   5.117          // the _threshold so that we'll come back to scan this object
   5.118 @@ -6890,7 +6897,7 @@
   5.119            if (_threshold < end_card_addr) {
   5.120              _threshold = end_card_addr;
   5.121            }
   5.122 -          if (p->klass() != NULL) {
   5.123 +          if (p->klass_or_null() != NULL) {
   5.124              // Redirty the range of cards...
   5.125              _mut->mark_range(redirty_range);
   5.126            } // ...else the setting of klass will dirty the card anyway.
   5.127 @@ -7048,7 +7055,7 @@
   5.128      assert(_skip_bits == 0, "tautology");
   5.129      _skip_bits = 2;  // skip next two marked bits ("Printezis-marks")
   5.130      oop p = oop(addr);
   5.131 -    if (p->klass() == NULL || !p->is_parsable()) {
   5.132 +    if (p->klass_or_null() == NULL || !p->is_parsable()) {
   5.133        // in the case of Clean-on-Enter optimization, redirty card
   5.134        // and avoid clearing card by increasing  the threshold.
   5.135        return;
   5.136 @@ -8023,7 +8030,7 @@
   5.137             "alignment problem");
   5.138  
   5.139      #ifdef DEBUG
   5.140 -      if (oop(addr)->klass() != NULL &&
   5.141 +      if (oop(addr)->klass_or_null() != NULL &&
   5.142            (   !_collector->should_unload_classes()
   5.143             || oop(addr)->is_parsable())) {
   5.144          // Ignore mark word because we are running concurrent with mutators
   5.145 @@ -8036,7 +8043,7 @@
   5.146  
   5.147    } else {
   5.148      // This should be an initialized object that's alive.
   5.149 -    assert(oop(addr)->klass() != NULL &&
   5.150 +    assert(oop(addr)->klass_or_null() != NULL &&
   5.151             (!_collector->should_unload_classes()
   5.152              || oop(addr)->is_parsable()),
   5.153             "Should be an initialized object");
     6.1 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp	Fri Jun 06 11:47:26 2008 -0700
     6.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp	Mon Jun 09 11:51:19 2008 -0400
     6.3 @@ -22,88 +22,6 @@
     6.4   *
     6.5   */
     6.6  
     6.7 -//
     6.8 -// Free block maintenance for Concurrent Mark Sweep Generation
     6.9 -//
    6.10 -// The main data structure for free blocks are
    6.11 -// . an indexed array of small free blocks, and
    6.12 -// . a dictionary of large free blocks
    6.13 -//
    6.14 -
    6.15 -// No virtuals in FreeChunk (don't want any vtables).
    6.16 -
    6.17 -// A FreeChunk is merely a chunk that can be in a doubly linked list
    6.18 -// and has a size field. NOTE: FreeChunks are distinguished from allocated
    6.19 -// objects in two ways (by the sweeper). The second word (prev) has the
    6.20 -// LSB set to indicate a free chunk; allocated objects' klass() pointers
    6.21 -// don't have their LSB set. The corresponding bit in the CMSBitMap is
    6.22 -// set when the chunk is allocated. There are also blocks that "look free"
    6.23 -// but are not part of the free list and should not be coalesced into larger
    6.24 -// free blocks. These free blocks have their two LSB's set.
    6.25 -
    6.26 -class FreeChunk VALUE_OBJ_CLASS_SPEC {
    6.27 -  friend class VMStructs;
    6.28 -  FreeChunk* _next;
    6.29 -  FreeChunk* _prev;
    6.30 -  size_t     _size;
    6.31 -
    6.32 - public:
    6.33 -  NOT_PRODUCT(static const size_t header_size();)
    6.34 -  // Returns "true" if the "wrd", which is required to be the second word
    6.35 -  // of a block, indicates that the block represents a free chunk.
    6.36 -  static bool secondWordIndicatesFreeChunk(intptr_t wrd) {
    6.37 -    return (wrd & 0x1) == 0x1;
    6.38 -  }
    6.39 -  bool isFree()       const {
    6.40 -    return secondWordIndicatesFreeChunk((intptr_t)_prev);
    6.41 -  }
    6.42 -  bool cantCoalesce() const { return (((intptr_t)_prev) & 0x3) == 0x3; }
    6.43 -  FreeChunk* next()   const { return _next; }
    6.44 -  FreeChunk* prev()   const { return (FreeChunk*)(((intptr_t)_prev) & ~(0x3)); }
    6.45 -  debug_only(void* prev_addr() const { return (void*)&_prev; })
    6.46 -
    6.47 -  void linkAfter(FreeChunk* ptr) {
    6.48 -    linkNext(ptr);
    6.49 -    if (ptr != NULL) ptr->linkPrev(this);
    6.50 -  }
    6.51 -  void linkAfterNonNull(FreeChunk* ptr) {
    6.52 -    assert(ptr != NULL, "precondition violation");
    6.53 -    linkNext(ptr);
    6.54 -    ptr->linkPrev(this);
    6.55 -  }
    6.56 -  void linkNext(FreeChunk* ptr) { _next = ptr; }
    6.57 -  void linkPrev(FreeChunk* ptr) { _prev = (FreeChunk*)((intptr_t)ptr | 0x1); }
    6.58 -  void clearPrev()              { _prev = NULL; }
    6.59 -  void clearNext()              { _next = NULL; }
    6.60 -  void dontCoalesce()      {
    6.61 -    // the block should be free
    6.62 -    assert(isFree(), "Should look like a free block");
    6.63 -    _prev = (FreeChunk*)(((intptr_t)_prev) | 0x2);
    6.64 -  }
    6.65 -  void markFree()    { _prev = (FreeChunk*)((intptr_t)_prev | 0x1);    }
    6.66 -  void markNotFree() { _prev = NULL; }
    6.67 -
    6.68 -  size_t size()           const { return _size; }
    6.69 -  void setSize(size_t size)     { _size = size; }
    6.70 -
    6.71 -  // For volatile reads:
    6.72 -  size_t* size_addr()           { return &_size; }
    6.73 -
    6.74 -  // Return the address past the end of this chunk
    6.75 -  HeapWord* end() const { return ((HeapWord*) this) + _size; }
    6.76 -
    6.77 -  // debugging
    6.78 -  void verify()             const PRODUCT_RETURN;
    6.79 -  void verifyList()         const PRODUCT_RETURN;
    6.80 -  void mangleAllocated(size_t size) PRODUCT_RETURN;
    6.81 -  void mangleFreed(size_t size)     PRODUCT_RETURN;
    6.82 -};
    6.83 -
    6.84 -// Alignment helpers etc.
    6.85 -#define numQuanta(x,y) ((x+y-1)/y)
    6.86 -enum AlignmentConstants {
    6.87 -  MinChunkSize = numQuanta(sizeof(FreeChunk), MinObjAlignmentInBytes) * MinObjAlignment
    6.88 -};
    6.89  
    6.90  // A FreeBlockDictionary is an abstract superclass that will allow
    6.91  // a number of alternative implementations in the future.
     7.1 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp	Fri Jun 06 11:47:26 2008 -0700
     7.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp	Mon Jun 09 11:51:19 2008 -0400
     7.3 @@ -47,15 +47,15 @@
     7.4    Copy::fill_to_words(addr + hdr, size - hdr, baadbabeHeapWord);
     7.5  }
     7.6  
     7.7 -void FreeChunk::mangleFreed(size_t size) {
     7.8 +void FreeChunk::mangleFreed(size_t sz) {
     7.9    assert(baadbabeHeapWord != deadbeefHeapWord, "Need distinct patterns");
    7.10    // mangle all but the header of a just-freed block of storage
    7.11    // just prior to passing it to the storage dictionary
    7.12 -  assert(size >= MinChunkSize, "smallest size of object");
    7.13 -  assert(size == _size, "just checking");
    7.14 +  assert(sz >= MinChunkSize, "smallest size of object");
    7.15 +  assert(sz == size(), "just checking");
    7.16    HeapWord* addr = (HeapWord*)this;
    7.17    size_t hdr = header_size();
    7.18 -  Copy::fill_to_words(addr + hdr, size - hdr, deadbeefHeapWord);
    7.19 +  Copy::fill_to_words(addr + hdr, sz - hdr, deadbeefHeapWord);
    7.20  }
    7.21  
    7.22  void FreeChunk::verifyList() const {
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp	Mon Jun 09 11:51:19 2008 -0400
     8.3 @@ -0,0 +1,137 @@
     8.4 +/*
     8.5 + * Copyright 2001-2005 Sun Microsystems, Inc.  All Rights Reserved.
     8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     8.7 + *
     8.8 + * This code is free software; you can redistribute it and/or modify it
     8.9 + * under the terms of the GNU General Public License version 2 only, as
    8.10 + * published by the Free Software Foundation.
    8.11 + *
    8.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    8.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    8.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    8.15 + * version 2 for more details (a copy is included in the LICENSE file that
    8.16 + * accompanied this code).
    8.17 + *
    8.18 + * You should have received a copy of the GNU General Public License version
    8.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    8.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    8.21 + *
    8.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    8.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
    8.24 + * have any questions.
    8.25 + *
    8.26 + */
    8.27 +
    8.28 +//
    8.29 +// Free block maintenance for Concurrent Mark Sweep Generation
    8.30 +//
    8.31 +// The main data structure for free blocks are
    8.32 +// . an indexed array of small free blocks, and
    8.33 +// . a dictionary of large free blocks
    8.34 +//
    8.35 +
    8.36 +// No virtuals in FreeChunk (don't want any vtables).
    8.37 +
    8.38 +// A FreeChunk is merely a chunk that can be in a doubly linked list
    8.39 +// and has a size field. NOTE: FreeChunks are distinguished from allocated
    8.40 +// objects in two ways (by the sweeper), depending on whether the VM is 32 or
    8.41 +// 64 bits.
    8.42 +// In 32 bits or 64 bits without CompressedOops, the second word (prev) has the
    8.43 +// LSB set to indicate a free chunk; allocated objects' klass() pointers
    8.44 +// don't have their LSB set. The corresponding bit in the CMSBitMap is
    8.45 +// set when the chunk is allocated. There are also blocks that "look free"
    8.46 +// but are not part of the free list and should not be coalesced into larger
    8.47 +// free blocks. These free blocks have their two LSB's set.
    8.48 +
    8.49 +class FreeChunk VALUE_OBJ_CLASS_SPEC {
    8.50 +  friend class VMStructs;
    8.51 +  // For 64 bit compressed oops, the markOop encodes both the size and the
    8.52 +  // indication that this is a FreeChunk and not an object.
    8.53 +  volatile size_t   _size;
    8.54 +  FreeChunk* _prev;
    8.55 +  FreeChunk* _next;
    8.56 +
    8.57 +  markOop mark()     const volatile { return (markOop)_size; }
    8.58 +  void set_mark(markOop m)          { _size = (size_t)m; }
    8.59 +
    8.60 + public:
    8.61 +  NOT_PRODUCT(static const size_t header_size();)
    8.62 +
    8.63 +  // Returns "true" if the address indicates that the block represents
    8.64 +  // a free chunk.
    8.65 +  static bool indicatesFreeChunk(const HeapWord* addr) {
    8.66 +    // Force volatile read from addr because value might change between
    8.67 +    // calls.  We really want the read of _mark and _prev from this pointer
    8.68 +    // to be volatile but making the fields volatile causes all sorts of
    8.69 +    // compilation errors.
    8.70 +    return ((volatile FreeChunk*)addr)->isFree();
    8.71 +  }
    8.72 +
    8.73 +  bool isFree() const volatile {
    8.74 +    LP64_ONLY(if (UseCompressedOops) return mark()->is_cms_free_chunk(); else)
    8.75 +    return (((intptr_t)_prev) & 0x1) == 0x1;
    8.76 +  }
    8.77 +  bool cantCoalesce() const {
    8.78 +    assert(isFree(), "can't get coalesce bit on not free");
    8.79 +    return (((intptr_t)_prev) & 0x2) == 0x2;
    8.80 +  }
    8.81 +  void dontCoalesce() {
    8.82 +    // the block should be free
    8.83 +    assert(isFree(), "Should look like a free block");
    8.84 +    _prev = (FreeChunk*)(((intptr_t)_prev) | 0x2);
    8.85 +  }
    8.86 +  FreeChunk* prev() const {
    8.87 +    return (FreeChunk*)(((intptr_t)_prev) & ~(0x3));
    8.88 +  }
    8.89 +
    8.90 +  debug_only(void* prev_addr() const { return (void*)&_prev; })
    8.91 +
    8.92 +  size_t size() const volatile {
    8.93 +    LP64_ONLY(if (UseCompressedOops) return mark()->get_size(); else )
    8.94 +    return _size;
    8.95 +  }
    8.96 +  void setSize(size_t sz) {
    8.97 +    LP64_ONLY(if (UseCompressedOops) set_mark(markOopDesc::set_size_and_free(sz)); else )
    8.98 +    _size = sz;
    8.99 +  }
   8.100 +
   8.101 +  FreeChunk* next()   const { return _next; }
   8.102 +
   8.103 +  void linkAfter(FreeChunk* ptr) {
   8.104 +    linkNext(ptr);
   8.105 +    if (ptr != NULL) ptr->linkPrev(this);
   8.106 +  }
   8.107 +  void linkAfterNonNull(FreeChunk* ptr) {
   8.108 +    assert(ptr != NULL, "precondition violation");
   8.109 +    linkNext(ptr);
   8.110 +    ptr->linkPrev(this);
   8.111 +  }
   8.112 +  void linkNext(FreeChunk* ptr) { _next = ptr; }
   8.113 +  void linkPrev(FreeChunk* ptr) {
   8.114 +     LP64_ONLY(if (UseCompressedOops) _prev = ptr; else)
   8.115 +     _prev = (FreeChunk*)((intptr_t)ptr | 0x1);
   8.116 +  }
   8.117 +  void clearPrev()              { _prev = NULL; }
   8.118 +  void clearNext()              { _next = NULL; }
   8.119 +  void markNotFree() {
   8.120 +   LP64_ONLY(if (UseCompressedOops) set_mark(markOopDesc::prototype());)
   8.121 +   // Also set _prev to null
   8.122 +   _prev = NULL;
   8.123 +  }
   8.124 +
   8.125 +  // Return the address past the end of this chunk
   8.126 +  HeapWord* end() const { return ((HeapWord*) this) + size(); }
   8.127 +
   8.128 +  // debugging
   8.129 +  void verify()             const PRODUCT_RETURN;
   8.130 +  void verifyList()         const PRODUCT_RETURN;
   8.131 +  void mangleAllocated(size_t size) PRODUCT_RETURN;
   8.132 +  void mangleFreed(size_t size)     PRODUCT_RETURN;
   8.133 +};
   8.134 +
   8.135 +// Alignment helpers etc.
   8.136 +#define numQuanta(x,y) ((x+y-1)/y)
   8.137 +enum AlignmentConstants {
   8.138 +  MinChunkSize = numQuanta(sizeof(FreeChunk), MinObjAlignmentInBytes) * MinObjAlignment
   8.139 +};
   8.140 +
     9.1 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp	Fri Jun 06 11:47:26 2008 -0700
     9.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp	Mon Jun 09 11:51:19 2008 -0400
     9.3 @@ -23,6 +23,7 @@
     9.4   */
     9.5  
     9.6  #define VM_STRUCTS_CMS(nonstatic_field, \
     9.7 +                   volatile_nonstatic_field, \
     9.8                     static_field) \
     9.9    nonstatic_field(CompactibleFreeListSpace,    _collector,                                    CMSCollector*)                         \
    9.10    nonstatic_field(CompactibleFreeListSpace,    _bt,                                           BlockOffsetArrayNonContigSpace)        \
    9.11 @@ -36,9 +37,9 @@
    9.12    nonstatic_field(CMSCollector,                _markBitMap,                                   CMSBitMap)                             \
    9.13    nonstatic_field(ConcurrentMarkSweepGeneration, _cmsSpace,                                   CompactibleFreeListSpace*)             \
    9.14       static_field(ConcurrentMarkSweepThread,   _collector,                                    CMSCollector*)                         \
    9.15 +  volatile_nonstatic_field(FreeChunk,          _size,                                         size_t)                                \
    9.16    nonstatic_field(FreeChunk,                   _next,                                         FreeChunk*)                            \
    9.17 -  nonstatic_field(FreeChunk,                   _prev,                                         FreeChunk*)                            \
    9.18 -  nonstatic_field(FreeChunk,                   _size,                                         size_t)
    9.19 +  nonstatic_field(FreeChunk,                   _prev,                                         FreeChunk*)
    9.20  
    9.21  #define VM_TYPES_CMS(declare_type,                                        \
    9.22                       declare_toplevel_type)                               \
    10.1 --- a/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep	Fri Jun 06 11:47:26 2008 -0700
    10.2 +++ b/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep	Mon Jun 09 11:51:19 2008 -0400
    10.3 @@ -206,6 +206,7 @@
    10.4  
    10.5  freeBlockDictionary.hpp                 allocation.hpp
    10.6  freeBlockDictionary.hpp                 debug.hpp
    10.7 +freeBlockDictionary.hpp                 freeChunk.hpp
    10.8  freeBlockDictionary.hpp                 globalDefinitions.hpp
    10.9  freeBlockDictionary.hpp                 memRegion.hpp
   10.10  freeBlockDictionary.hpp                 mutex.hpp
   10.11 @@ -214,6 +215,14 @@
   10.12  freeChunk.cpp                           copy.hpp
   10.13  freeChunk.cpp                           freeBlockDictionary.hpp
   10.14  
   10.15 +freeChunk.hpp                           allocation.hpp
   10.16 +freeChunk.hpp                           debug.hpp
   10.17 +freeChunk.hpp                           globalDefinitions.hpp
   10.18 +freeChunk.hpp                           markOop.hpp
   10.19 +freeChunk.hpp                           memRegion.hpp
   10.20 +freeChunk.hpp                           mutex.hpp
   10.21 +freeChunk.hpp                           ostream.hpp
   10.22 +
   10.23  freeList.cpp                            freeBlockDictionary.hpp
   10.24  freeList.cpp                            freeList.hpp
   10.25  freeList.cpp                            globals.hpp
    11.1 --- a/src/share/vm/oops/markOop.hpp	Fri Jun 06 11:47:26 2008 -0700
    11.2 +++ b/src/share/vm/oops/markOop.hpp	Mon Jun 09 11:51:19 2008 -0400
    11.3 @@ -29,8 +29,10 @@
    11.4  //
    11.5  // Bit-format of an object header (most significant first):
    11.6  //
    11.7 -//
    11.8 -//  unused:0/25 hash:25/31 age:4 biased_lock:1 lock:2 = 32/64 bits
    11.9 +//  32 bits: unused:0  hash:25 age:4 biased_lock:1 lock:2
   11.10 +//  64 bits: unused:24 hash:31 cms:2 age:4 biased_lock:1 lock:2
   11.11 +//           unused:20 size:35 cms:2 age:4 biased_lock:1 lock:2 (if cms
   11.12 +//                                                               free chunk)
   11.13  //
   11.14  //  - hash contains the identity hash value: largest value is
   11.15  //    31 bits, see os::random().  Also, 64-bit vm's require
   11.16 @@ -91,6 +93,7 @@
   11.17           biased_lock_bits         = 1,
   11.18           max_hash_bits            = BitsPerWord - age_bits - lock_bits - biased_lock_bits,
   11.19           hash_bits                = max_hash_bits > 31 ? 31 : max_hash_bits,
   11.20 +         cms_bits                 = LP64_ONLY(1) NOT_LP64(0),
   11.21           epoch_bits               = 2
   11.22    };
   11.23  
   11.24 @@ -106,7 +109,8 @@
   11.25    enum { lock_shift               = 0,
   11.26           biased_lock_shift        = lock_bits,
   11.27           age_shift                = lock_bits + biased_lock_bits,
   11.28 -         hash_shift               = lock_bits + biased_lock_bits + age_bits,
   11.29 +         cms_shift                = age_shift + age_bits,
   11.30 +         hash_shift               = cms_shift + cms_bits,
   11.31           epoch_shift              = hash_shift
   11.32    };
   11.33  
   11.34 @@ -118,7 +122,9 @@
   11.35           age_mask                 = right_n_bits(age_bits),
   11.36           age_mask_in_place        = age_mask << age_shift,
   11.37           epoch_mask               = right_n_bits(epoch_bits),
   11.38 -         epoch_mask_in_place      = epoch_mask << epoch_shift
   11.39 +         epoch_mask_in_place      = epoch_mask << epoch_shift,
   11.40 +         cms_mask                 = right_n_bits(cms_bits),
   11.41 +         cms_mask_in_place        = cms_mask << cms_shift
   11.42  #ifndef _WIN64
   11.43           ,hash_mask               = right_n_bits(hash_bits),
   11.44           hash_mask_in_place       = (address_word)hash_mask << hash_shift
   11.45 @@ -360,4 +366,40 @@
   11.46  
   11.47    // see the definition in markOop.cpp for the gory details
   11.48    bool should_not_be_cached() const;
   11.49 +
   11.50 +  // These markOops indicate cms free chunk blocks and not objects.
   11.51 +  // In 64 bit, the markOop is set to distinguish them from oops.
   11.52 +  // These are defined in 32 bit mode for vmStructs.
   11.53 +  const static uintptr_t cms_free_chunk_pattern  = 0x1;
   11.54 +
   11.55 +  // Constants for the size field.
   11.56 +  enum { size_shift                = cms_shift + cms_bits,
   11.57 +         size_bits                 = 35    // need for compressed oops 32G
   11.58 +       };
   11.59 +  // These values are too big for Win64
   11.60 +  const static uintptr_t size_mask = LP64_ONLY(right_n_bits(size_bits))
   11.61 +                                     NOT_LP64(0);
   11.62 +  const static uintptr_t size_mask_in_place =
   11.63 +                                     (address_word)size_mask << size_shift;
   11.64 +
   11.65 +#ifdef _LP64
   11.66 +  static markOop cms_free_prototype() {
   11.67 +    return markOop(((intptr_t)prototype() & ~cms_mask_in_place) |
   11.68 +                   ((cms_free_chunk_pattern & cms_mask) << cms_shift));
   11.69 +  }
   11.70 +  uintptr_t cms_encoding() const {
   11.71 +    return mask_bits(value() >> cms_shift, cms_mask);
   11.72 +  }
   11.73 +  bool is_cms_free_chunk() const {
   11.74 +    return is_neutral() &&
   11.75 +           (cms_encoding() & cms_free_chunk_pattern) == cms_free_chunk_pattern;
   11.76 +  }
   11.77 +
   11.78 +  size_t get_size() const       { return (size_t)(value() >> size_shift); }
   11.79 +  static markOop set_size_and_free(size_t size) {
   11.80 +    assert((size & ~size_mask) == 0, "shouldn't overflow size field");
   11.81 +    return markOop(((intptr_t)cms_free_prototype() & ~size_mask_in_place) |
   11.82 +                   (((intptr_t)size & size_mask) << size_shift));
   11.83 +  }
   11.84 +#endif // _LP64
   11.85  };
    12.1 --- a/src/share/vm/runtime/arguments.cpp	Fri Jun 06 11:47:26 2008 -0700
    12.2 +++ b/src/share/vm/runtime/arguments.cpp	Mon Jun 09 11:51:19 2008 -0400
    12.3 @@ -1174,7 +1174,7 @@
    12.4    // field offset to determine free list chunk markers.
    12.5    // Check that UseCompressedOops can be set with the max heap size allocated
    12.6    // by ergonomics.
    12.7 -  if (!UseConcMarkSweepGC && MaxHeapSize <= max_heap_for_compressed_oops()) {
    12.8 +  if (MaxHeapSize <= max_heap_for_compressed_oops()) {
    12.9      if (FLAG_IS_DEFAULT(UseCompressedOops)) {
   12.10        // Leave compressed oops off by default. Uncomment
   12.11        // the following line to return it to default status.
    13.1 --- a/src/share/vm/runtime/vmStructs.cpp	Fri Jun 06 11:47:26 2008 -0700
    13.2 +++ b/src/share/vm/runtime/vmStructs.cpp	Mon Jun 09 11:51:19 2008 -0400
    13.3 @@ -1694,7 +1694,12 @@
    13.4    declare_constant(markOopDesc::no_hash)                                  \
    13.5    declare_constant(markOopDesc::no_hash_in_place)                         \
    13.6    declare_constant(markOopDesc::no_lock_in_place)                         \
    13.7 -  declare_constant(markOopDesc::max_age)
    13.8 +  declare_constant(markOopDesc::max_age)                                  \
    13.9 +                                                                          \
   13.10 +  /* Constants in markOop used by CMS. */                                 \
   13.11 +  declare_constant(markOopDesc::cms_shift)                                \
   13.12 +  declare_constant(markOopDesc::cms_mask)                                 \
   13.13 +  declare_constant(markOopDesc::size_shift)                               \
   13.14  
   13.15    /* NOTE that we do not use the last_entry() macro here; it is used   */
   13.16    /* in vmStructs_<os>_<cpu>.hpp's VM_LONG_CONSTANTS_OS_CPU macro (and */
   13.17 @@ -1958,6 +1963,7 @@
   13.18                          GENERATE_STATIC_VM_STRUCT_ENTRY)
   13.19  
   13.20    VM_STRUCTS_CMS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \
   13.21 +                 GENERATE_NONSTATIC_VM_STRUCT_ENTRY, \
   13.22                   GENERATE_STATIC_VM_STRUCT_ENTRY)
   13.23  #endif // SERIALGC
   13.24  
   13.25 @@ -2099,6 +2105,7 @@
   13.26               CHECK_STATIC_VM_STRUCT_ENTRY);
   13.27  
   13.28    VM_STRUCTS_CMS(CHECK_NONSTATIC_VM_STRUCT_ENTRY,
   13.29 +             CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY,
   13.30               CHECK_STATIC_VM_STRUCT_ENTRY);
   13.31  #endif // SERIALGC
   13.32  
   13.33 @@ -2203,6 +2210,7 @@
   13.34    debug_only(VM_STRUCTS_PARALLELGC(ENSURE_FIELD_TYPE_PRESENT, \
   13.35                                     ENSURE_FIELD_TYPE_PRESENT));
   13.36    debug_only(VM_STRUCTS_CMS(ENSURE_FIELD_TYPE_PRESENT, \
   13.37 +                            ENSURE_FIELD_TYPE_PRESENT, \
   13.38                              ENSURE_FIELD_TYPE_PRESENT));
   13.39  #endif // SERIALGC
   13.40    debug_only(VM_STRUCTS_CPU(ENSURE_FIELD_TYPE_PRESENT, \

mercurial