package s3.core.services.memory.JMTk;

import ovm.core.services.memory.VM_Area;
import ovm.core.services.memory.VM_Address;
import s3.core.services.memory.vmInterface.VM_Interface;
import ovm.core.domain.Oop;

public class MemoryArea extends VM_Area{
  private int prange;
  private int crange;
  private BumpPointer allocator;
  private VM_Address start;
  private boolean destroyed;
  private int bytes;
  public static MemoryArea heap;
  public static MemoryArea immortal;

  static{
    heap = new MemoryArea(VM_Interface.getPlan().getHeapAllocator());
    immortal = new MemoryArea(VM_Interface.getPlan().getImmortalAllocator());
  }

  public MemoryArea(Oop mirror){
    super(mirror);
    destroyed = false;
  }
  
  public MemoryArea(Oop mirror, int size) {
    super(mirror);
    allocator = VM_Interface.getPlan().getScopeAllocator(size, this);
    destroyed = false;
    bytes = size;
  }

  public MemoryArea(BumpPointer alloc){
    super(null);
    allocator = alloc;
    destroyed = false;
  }
  
  /* This method should not be called outside of the memory manager.
   */
  public VM_Address getMem(int size){
    return allocator.alloc(false, size);
  }
  
  public void setRange(short min, short max) {
    prange = (min << 16)|max|MSK;
    crange = (min << 16)|max;
  }
  
  /**
   * Free all object managed by this area.  Subsequent
   * allocations from this area will reuse their storage.
   **/
  public void reset(){
    allocator.setCursor(start);
  }
  
  /**
   * Travel back to the time when memoryConsumed() == newOffset,
   * freeing all objects that where subsequently allocated in this
   * area.
   * <p>
   * The argument should be &lt;= the current value of
   * memoryConsumed().
   *
   * @param newOffset the new allocation offset
   **/
  public void reset(int newOffset){
    allocator.setCursor(start.add(newOffset));
  }
  
  /**
   * Destroy this allocator and return its memory to the system.
   **/
  public void destroy(){
    destroyed = true;
    VM_Interface.getPlan().freeScope(start, this);
  }
  
  public int size(){
    return bytes;
  }

  public int memoryConsumed(){
    return allocator.memoryConsumed(start);
  }
  
  /**
   * Are objects in this area still live (ie, has the destroy method been called)
   * @return true if the destroy method has not been called
   **/
  public boolean isLive(){
    return !destroyed;
  }

  public void setStartAddress(VM_Address a){
    start = a;
  }

    public VM_Address getBaseAddress() {
	return start;
    }

  public BumpPointer getAllocator(){
    return allocator;
  }

  public boolean rangeCheck(MemoryArea tgt) {
    if(tgt == this) return true;
    return (((tgt.prange - this.crange) & VM_Area.MSK) != VM_Area.RES);
  }

  public static VM_Area getHeapArea(){
    return heap;
  }

  public static VM_Area getImmortalArea(){
    return immortal;
  }
}
