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