1 /*
   2  * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * 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    // for free size, three fields
  39    //       FreeBlockDictionary* _dictionary;        // ptr to dictionary for large size blocks
  40    //       FreeList _indexedFreeList[IndexSetSize]; // indexed array for small size blocks
  41    //       LinearAllocBlock _smallLinearAllocBlock; // small linear alloc in TLAB
  42    private static AddressField indexedFreeListField;
  43    private static AddressField dictionaryField;
  44    private static long         smallLinearAllocBlockFieldOffset;
  45    private static long indexedFreeListSizeOf;
  46 
  47    private int    heapWordSize;     // 4 for 32bit, 8 for 64 bits
  48    private int    IndexSetStart;    // for small indexed list
  49    private int    IndexSetSize;
  50    private int    IndexSetStride;
  51 
  52    static {
  53       VM.registerVMInitializedObserver(new Observer() {
  54          public void update(Observable o, Object data) {
  55             initialize(VM.getVM().getTypeDataBase());
  56          }
  57       });
  58    }
  59 
  60    private static synchronized void initialize(TypeDataBase db) {
  61       long sizeofFreeChunk = db.lookupType("FreeChunk").getSize();
  62       VM vm = VM.getVM();
  63       MinChunkSizeInBytes = numQuanta(sizeofFreeChunk, vm.getMinObjAlignmentInBytes()) *
  64                      vm.getMinObjAlignmentInBytes();
  65 
  66      Type type = db.lookupType("CompactibleFreeListSpace");
  67      collectorField = type.getAddressField("_collector");
  68      collectorField       = type.getAddressField("_collector");
  69      dictionaryField      = type.getAddressField("_dictionary");
  70      indexedFreeListField = type.getAddressField("_indexedFreeList[0]");
  71      smallLinearAllocBlockFieldOffset = type.getField("_smallLinearAllocBlock").getOffset();
  72    }
  73 
  74    public CompactibleFreeListSpace(Address addr) {
  75       super(addr);
  76       VM vm = VM.getVM();
  77       heapWordSize   = vm.getHeapWordSize();
  78       IndexSetStart  = vm.getMinObjAlignmentInBytes() / heapWordSize;
  79       IndexSetStride = IndexSetStart;
  80       IndexSetSize   = 257;
  81    }
  82 
  83    // Accessing block offset table
  84    public CMSCollector collector() {
  85     return (CMSCollector) VMObjectFactory.newObject(
  86                                  CMSCollector.class,
  87                                  collectorField.getValue(addr));
  88    }
  89 
  90    public long free0() {
  91      return capacity() - used0();
  92    }
  93 
  94    public long used() {
  95      return capacity() - free();
  96    }
  97 
  98    public long used0() {
  99       List regions = getLiveRegions();
 100       long usedSize = 0L;
 101       for (Iterator itr = regions.iterator(); itr.hasNext();) {
 102          MemRegion mr = (MemRegion) itr.next();
 103          usedSize += mr.byteSize();
 104       }
 105       return usedSize;
 106    }
 107 
 108    public long free() {
 109       // small chunks
 110       long size = 0;
 111       Address cur = addr.addOffsetTo( indexedFreeListField.getOffset() );
 112       cur = cur.addOffsetTo(IndexSetStart*FreeList.sizeOf());
 113       for (int i=IndexSetStart; i<IndexSetSize; i += IndexSetStride) {
 114          FreeList freeList = (FreeList) VMObjectFactory.newObject(FreeList.class, cur);
 115          size += i*freeList.count();
 116          cur= cur.addOffsetTo(IndexSetStride*FreeList.sizeOf());
 117       }
 118 
 119       // large block
 120       AFLBinaryTreeDictionary aflbd = (AFLBinaryTreeDictionary) VMObjectFactory.newObject(AFLBinaryTreeDictionary.class,
 121                                                                                    dictionaryField.getValue(addr));
 122       size += aflbd.size();
 123 
 124 
 125       // linear block in TLAB
 126       LinearAllocBlock lab = (LinearAllocBlock) VMObjectFactory.newObject(LinearAllocBlock.class,
 127                                                                           addr.addOffsetTo(smallLinearAllocBlockFieldOffset));
 128       size += lab.word_size();
 129 
 130       return size*heapWordSize;
 131   }
 132 
 133    public void printOn(PrintStream tty) {
 134       tty.print("free-list-space");
 135       tty.print("[ " + bottom() + " , " + end() + " ) ");
 136       long cap = capacity();
 137       long used_size = used();
 138       long free_size = free();
 139       int  used_perc = (int)((double)used_size/cap*100);
 140       tty.print("space capacity = " + cap + " used(" + used_perc + "%)= " + used_size + " ");
 141       tty.print("free= " + free_size );
 142       tty.print("\n");
 143 
 144    }
 145 
 146    public Address skipBlockSizeUsingPrintezisBits(Address pos) {
 147        CMSCollector collector = collector();
 148        long size = 0;
 149        Address addr = null;
 150 
 151        if (collector != null) {
 152          size = collector.blockSizeUsingPrintezisBits(pos);
 153          if (size >= 3) {
 154            addr = pos.addOffsetTo(adjustObjectSizeInBytes(size));
 155          }
 156        }
 157        return addr;
 158    }
 159 
 160    public List/*<MemRegion>*/ getLiveRegions() {
 161       List res = new ArrayList(); // List<MemRegion>
 162       VM vm = VM.getVM();
 163       Debugger dbg = vm.getDebugger();
 164       ObjectHeap heap = vm.getObjectHeap();
 165       Address cur = bottom();
 166       Address regionStart = cur;
 167       Address limit = end();
 168       final long addressSize = vm.getAddressSize();
 169 
 170       for (; cur.lessThan(limit);) {
 171          Address k = cur.getAddressAt(addressSize);
 172          if (FreeChunk.indicatesFreeChunk(cur)) {
 173             if (! cur.equals(regionStart)) {
 174                res.add(new MemRegion(regionStart, cur));
 175             }
 176             FreeChunk fc = (FreeChunk) VMObjectFactory.newObject(FreeChunk.class, cur);
 177             long chunkSize = fc.size();
 178             if (Assert.ASSERTS_ENABLED) {
 179                Assert.that(chunkSize > 0, "invalid FreeChunk size");
 180             }
 181             // note that fc.size() gives chunk size in heap words
 182             cur = cur.addOffsetTo(chunkSize * addressSize);
 183             regionStart = cur;
 184          } else if (k != null) {
 185             Oop obj = heap.newOop(cur.addOffsetToAsOopHandle(0));
 186             long objectSize = obj.getObjectSize();
 187             cur = cur.addOffsetTo(adjustObjectSizeInBytes(objectSize));
 188          } else {
 189             // FIXME: need to do a better job here.
 190             // can I use bitMap here?
 191             //Find the object size using Printezis bits and skip over
 192             long size = collector().blockSizeUsingPrintezisBits(cur);
 193             if (size == -1) {
 194               break;
 195             }
 196             cur = cur.addOffsetTo(adjustObjectSizeInBytes(size));
 197          }
 198       }
 199       return res;
 200    }
 201 
 202    //-- Internals only below this point
 203 
 204    // Unlike corresponding VM code, we operate on byte size rather than
 205    // HeapWord size for convenience.
 206 
 207    private static long numQuanta(long x, long y) {
 208       return  ((x+y-1)/y);
 209    }
 210 
 211    public static long adjustObjectSizeInBytes(long sizeInBytes) {
 212       return Oop.alignObjectSize(Math.max(sizeInBytes, MinChunkSizeInBytes));
 213    }
 214 
 215    // FIXME: should I read this directly from VM?
 216    private static long MinChunkSizeInBytes;
 217 }