/*
 * (C) Copyright Department of Computer Science,
 * Australian National University. 2002
 */

package s3.core.services.memory.JMTk;

import s3.core.services.memory.vmInterface.VM_Interface;
import s3.core.services.memory.vmInterface.Constants;
//import s3.core.services.memory.vmInterface.Statistics;

import ovm.core.services.memory.VM_Address;

/**
 * This abstract base class provides the basis for processor-local
 * allocation.  The key functionality provided is the retry mechanism
 * that is necessary to correctly handle the fact that a "slow-path"
 * allocation can cause a GC which violate the uninterruptability assumption.
 * This results in the thread being moved to a different processor so that
 * the allocator object it is using is not actually the one for the processor
 * it is running on.
 *
 * Failing to handle this properly will lead to very hard to trace bugs
 * where the allocation that caused a GC or allocations immediately following
 * GC are run incorrectly.
 *
 * @author Perry Cheng
 * @version $Revision: 1.4 $
 * @date $Date: 2004/02/16 19:29:11 $
 */

abstract class Allocator implements Constants, VM_Uninterruptible {
  public final static String Id = "$Id: Allocator.java,v 1.4 2004/02/16 19:29:11 pmcgache Exp $"; 

  /**
   * Maximum number of retries on consecutive allocation failure.
   *
   */
  private static final int MAX_RETRY = 5;

  /**
   * Constructor
   *
   */
  Allocator () {
  }

  abstract protected VM_Address allocSlowOnce (boolean isScalar, int bytes,
					       boolean inGC);

  public VM_Address allocSlow(boolean isScalar, int bytes) 
    throws VM_PragmaNoInline { 
    return allocSlowBody(isScalar, bytes, false);
  }
  public VM_Address allocSlow(boolean isScalar, int bytes, boolean inGC) 
    throws VM_PragmaNoInline { 
    return allocSlowBody(isScalar, bytes, inGC);
  }
  private VM_Address allocSlowBody(boolean isScalar, int bytes, boolean inGC) 
    throws VM_PragmaInline { 

    //    int gcCountStart = Statistics.gcCount;
    Allocator current = this;
    for (int i=0; i<MAX_RETRY; i++) {
      VM_Address result = current.allocSlowOnce(isScalar, bytes, inGC);
      if (!result.isNull())
	return result;
      current = BasePlan.getOwnAllocator(current);
    }
    ovm.core.execution.Native.print_string("GC Warning: OutOfMemory from allocSlowBody - possible VM range imbalance - space ");
    ovm.core.execution.Native.print_int(Plan.getSpaceFromAllocatorAnyPlan(this));
    ovm.core.execution.Native.print_string("\n");
    //Log.write("gcCountStart = "); Log.writeln(gcCountStart);
    //Log.write("gcCount (now) = "); Log.writeln(Statistics.gcCount);
    //   VM_Interface.dumpStack(); 
    VM_Interface.failWithOutOfMemoryError();
    /* NOTREACHED */
    return VM_Address.fromInt(0);
  }

}
