1 /*
   2  * Copyright 2003-2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot.memory;
  26 
  27 import java.io.*;
  28 import java.util.*;
  29 import sun.jvm.hotspot.debugger.*;
  30 import sun.jvm.hotspot.oops.*;
  31 import sun.jvm.hotspot.runtime.*;
  32 import sun.jvm.hotspot.types.*;
  33 import sun.jvm.hotspot.utilities.*;
  34 
  35 public class CompactibleFreeListSpace extends CompactibleSpace {
  36    private static AddressField collectorField;
  37 
  38    static {
  39       VM.registerVMInitializedObserver(new Observer() {
  40          public void update(Observable o, Object data) {
  41             initialize(VM.getVM().getTypeDataBase());
  42          }
  43       });
  44    }
  45 
  46    private static synchronized void initialize(TypeDataBase db) {
  47       long sizeofFreeChunk = db.lookupType("FreeChunk").getSize();
  48       VM vm = VM.getVM();
  49       MinChunkSizeInBytes = numQuanta(sizeofFreeChunk, vm.getMinObjAlignmentInBytes()) *
  50                      vm.getMinObjAlignmentInBytes();
  51 
  52      Type type = db.lookupType("CompactibleFreeListSpace");
  53      collectorField = type.getAddressField("_collector");
  54    }
  55 
  56    public CompactibleFreeListSpace(Address addr) {
  57       super(addr);
  58    }
  59 
  60    // Accessing block offset table
  61    public CMSCollector collector() {
  62     return (CMSCollector) VMObjectFactory.newObject(
  63                                  CMSCollector.class,
  64                                  collectorField.getValue(addr));
  65   }
  66 
  67    public long used() {
  68       List regions = getLiveRegions();
  69       long usedSize = 0L;
  70       for (Iterator itr = regions.iterator(); itr.hasNext();) {
  71          MemRegion mr = (MemRegion) itr.next();
  72          usedSize += mr.byteSize();
  73       }
  74       return usedSize;
  75    }
  76 
  77    public long free() {
  78       return capacity() - used();
  79    }
  80 
  81    public void printOn(PrintStream tty) {
  82       tty.print("free-list-space");
  83    }
  84 
  85    public Address skipBlockSizeUsingPrintezisBits(Address pos) {
  86        CMSCollector collector = collector();
  87        long size = 0;
  88        Address addr = null;
  89 
  90        if (collector != null) {
  91          size = collector.blockSizeUsingPrintezisBits(pos);
  92          if (size >= 3) {
  93            addr = pos.addOffsetTo(adjustObjectSizeInBytes(size));
  94          }
  95        }
  96        return addr;
  97    }
  98 
  99    public List/*<MemRegion>*/ getLiveRegions() {
 100       List res = new ArrayList(); // List<MemRegion>
 101       VM vm = VM.getVM();
 102       Debugger dbg = vm.getDebugger();
 103       ObjectHeap heap = vm.getObjectHeap();
 104       Address cur = bottom();
 105       Address regionStart = cur;
 106       Address limit = end();
 107       final long addressSize = vm.getAddressSize();
 108 
 109       for (; cur.lessThan(limit);) {
 110          Address klassOop = cur.getAddressAt(addressSize);
 111          // FIXME: need to do a better job here.
 112          // can I use bitMap here?
 113          if (klassOop == null) {
 114             //Find the object size using Printezis bits and skip over
 115             System.err.println("Finding object size using Printezis bits and skipping over...");
 116             long size = collector().blockSizeUsingPrintezisBits(cur);
 117             if (size == -1) {
 118               System.err.println("Printezis bits not set...");
 119               break;
 120             }
 121             cur = cur.addOffsetTo(adjustObjectSizeInBytes(size));
 122          }
 123 
 124          if (FreeChunk.secondWordIndicatesFreeChunk(dbg.getAddressValue(klassOop))) {
 125             if (! cur.equals(regionStart)) {
 126                res.add(new MemRegion(regionStart, cur));
 127             }
 128             FreeChunk fc = (FreeChunk) VMObjectFactory.newObject(FreeChunk.class, cur);
 129             long chunkSize = fc.size();
 130             if (Assert.ASSERTS_ENABLED) {
 131                Assert.that(chunkSize > 0, "invalid FreeChunk size");
 132             }
 133             // note that fc.size() gives chunk size in heap words
 134             cur = cur.addOffsetTo(chunkSize * addressSize);
 135             System.err.println("Free chunk in CMS heap, size="+chunkSize * addressSize);
 136             regionStart = cur;
 137          } else if (klassOop != null) {
 138             Oop obj = heap.newOop(cur.addOffsetToAsOopHandle(0));
 139             long objectSize = obj.getObjectSize();
 140             cur = cur.addOffsetTo(adjustObjectSizeInBytes(objectSize));
 141          }
 142       }
 143       return res;
 144    }
 145 
 146    //-- Internals only below this point
 147 
 148    // Unlike corresponding VM code, we operate on byte size rather than
 149    // HeapWord size for convenience.
 150 
 151    private static long numQuanta(long x, long y) {
 152       return  ((x+y-1)/y);
 153    }
 154 
 155    public static long adjustObjectSizeInBytes(long sizeInBytes) {
 156       return Oop.alignObjectSize(Math.max(sizeInBytes, MinChunkSizeInBytes));
 157    }
 158 
 159    // FIXME: should I read this directly from VM?
 160    private static long MinChunkSizeInBytes;
 161 }