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

package sun.jvm.hotspot.memory;

import java.util.*;
import sun.jvm.hotspot.code.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;

public class CodeHeap extends VMObject {
  private static Field         memoryField;
  private static Field         segmapField;
  //  private static CIntegerField numberOfCommittedSegmentsField;
  //  private static CIntegerField numberOfReservedSegmentsField;
  //  private static CIntegerField segmentSizeField;
  private static CIntegerField log2SegmentSizeField;
  //  private static CIntegerField nextSegmentField;
  //  private static AddressField  freelistField;
  //  private static CIntegerField freeSegmentsField;

  private VirtualSpace memory;
  private VirtualSpace segmentMap;
  private int log2SegmentSize;

  static {
    VM.registerVMInitializedObserver(new Observer() {
        public void update(Observable o, Object data) {
          initialize(VM.getVM().getTypeDataBase());
        }
      });
  }

  private static void initialize(TypeDataBase db) {
    Type type = db.lookupType("CodeHeap");

    memoryField          = type.getField("_memory");
    segmapField          = type.getField("_segmap");
    log2SegmentSizeField = type.getCIntegerField("_log2_segment_size");

  }

  public CodeHeap(Address addr) {
    super(addr);
    log2SegmentSize = (int) log2SegmentSizeField.getValue(addr);
    segmentMap = new VirtualSpace(addr.addOffsetTo(segmapField.getOffset()));
    memory = new VirtualSpace(addr.addOffsetTo(memoryField.getOffset()));
  }

  public Address begin() {
    return getMemory().low();
  }

  public Address end() {
    return getMemory().high();
  }

  public boolean contains(Address p) {
    return (begin().lessThanOrEqual(p) && end().greaterThan(p));
  }

  
Returns the start of the block containing p or null
/** Returns the start of the block containing p or null */
public Address findStart(Address p) { if (!contains(p)) return null; HeapBlock h = blockStart(p); if (h == null || h.isFree()) { return null; } return h.getAllocatedSpace(); } private Address nextBlock(Address ptr) { Address base = blockBase(ptr); if (base == null) { return null; } HeapBlock block = getBlockAt(base); return base.addOffsetTo(block.getLength() * (1 << getLog2SegmentSize())); } public void iterate(CodeCacheVisitor visitor, CodeCache cache) { CodeBlob lastBlob = null; Address ptr = begin(); while (ptr != null && ptr.lessThan(end())) { try { // Use findStart to get a pointer inside blob other findBlob asserts CodeBlob blob = cache.createCodeBlobWrapper(findStart(ptr)); if (blob != null) { visitor.visit(blob); if (blob == lastBlob) { throw new InternalError("saw same blob twice"); } lastBlob = blob; } } catch (RuntimeException e) { e.printStackTrace(); } Address next = nextBlock(ptr); if (next != null && next.lessThan(ptr)) { throw new InternalError("pointer moved backwards"); } ptr = next; } } //-------------------------------------------------------------------------------- // Internals only below this point // private VirtualSpace getMemory() { return memory; } private VirtualSpace getSegmentMap() { return segmentMap; } private long segmentFor(Address p) { return p.minus(getMemory().low()) >> getLog2SegmentSize(); } private int getLog2SegmentSize() { return log2SegmentSize; } private HeapBlock getBlockAt(Address addr) { return (HeapBlock) VMObjectFactory.newObject(HeapBlock.class, addr); } private HeapBlock blockStart(Address p) { Address base = blockBase(p); if (base == null) return null; return getBlockAt(base); } private Address blockBase(Address p) { long i = segmentFor(p); Address b = getSegmentMap().low(); if (b.getCIntegerAt(i, 1, true) == 0xFF) { return null; } while (b.getCIntegerAt(i, 1, true) > 0) { i -= b.getCIntegerAt(i, 1, true); } return getMemory().low().addOffsetTo(i << getLog2SegmentSize()); } }