/*
 * (C) Copyright IBM Corp. 2001
 */
//$Id: MM_Interface.java,v 1.18 2005/09/26 05:01:50 dholmes Exp $

package s3.core.services.memory.vmInterface;

import ovm.core.domain.Blueprint;
import ovm.core.domain.Oop;
import ovm.core.execution.Context;
import ovm.core.execution.CoreServicesAccess;
import ovm.core.services.memory.MemoryManager;
import ovm.core.services.memory.NonPinningMemoryManager;
import ovm.core.services.memory.VM_Address;
import ovm.core.services.memory.VM_Area;
import ovm.util.CommandLine;
import s3.core.services.memory.JMTk.AllocAdvice;
import s3.core.services.memory.JMTk.HeapGrowthManager;
import s3.core.services.memory.JMTk.Memory;
import s3.core.services.memory.JMTk.MemoryArea;
import s3.core.services.memory.JMTk.Plan;
import s3.core.services.memory.JMTk.UnimplementedException;
import s3.core.services.memory.JMTk.VMResource;
import s3.core.services.memory.JMTk.VM_Magic;
import s3.core.services.memory.JMTk.VM_PragmaInline;
import s3.core.services.memory.JMTk.VM_PragmaInterruptible;
import s3.core.services.memory.JMTk.VM_PragmaUninterruptible;
import s3.core.services.memory.JMTk.VM_Uninterruptible;

import s3.util.PragmaAtomic;

/**
 * The interface that the JMTk memory manager presents to the Jikes
 * research virtual machine.
 * 
 * @author Perry Cheng
 * @version $Revision: 1.18 $
 * @date $Date: 2005/09/26 05:01:50 $
 */  
public class MM_Interface extends NonPinningMemoryManager
  implements Constants, VM_Uninterruptible {

  /***********************************************************************
   *
   * Class variables
   */

  /**
   * <code>true</code> if a write barrier is required.  Specifically,
   * if the memory manger requires that the virtual machine calls
   * putfieldWriteBarrier, arrayStoreWriteBarrier or modifyCheck when
   * the corresponding writes are done.
   * AJG: Is this correct?
   */
  public static final boolean NEEDS_WRITE_BARRIER = Plan.NEEDS_WRITE_BARRIER;

  /**
   * <code>true</code> if a write barrier for putstatic operations is
   * required.  Specifically, if the memory manger requires that the
   * virtual machine calls putstaticWriteBarrier, when a putstatic
   * operation is needed.
   * AJG: Is this correct?
   */
  public static final boolean NEEDS_PUTSTATIC_WRITE_BARRIER
    = Plan.NEEDS_PUTSTATIC_WRITE_BARRIER;

  /* AJG: Not used. But will be. needed */
  /**
   * <code>true</code> if a write barrier for TIB store operations is
   * requried.  Note: This field is not used.
   */
  public static final boolean NEEDS_TIB_STORE_WRITE_BARRIER
    = Plan.NEEDS_TIB_STORE_WRITE_BARRIER;

  /**
   * <code>true</code> if the memory manager moves objects. For
   * example, a copying collector will move objects.
   */
  public static final boolean MOVES_OBJECTS = Plan.MOVES_OBJECTS;

  /**
   * <code>true</code> if the memory manager moves type information
   * blocks (TIBs).
   */
  public static final boolean MOVES_TIBS = Plan.MOVES_TIBS;

  /**
   * <code>true</code> if checking of allocated memory to ensure it is
   * zeroed is desired.
   */
  private static final boolean CHECK_MEMORY_IS_ZEROED = false;

  /* AJG: Not used */
//   public static final boolean RC_CYCLE_DETECTION = Plan.REF_COUNT_CYCLE_DETECTION;

  /***********************************************************************
   *
   * Initialization
   */

  /**
   * Initialization that occurs at <i>build</i> time.  The value of
   * statics as at the completion of this routine will be reflected in
   * the boot image.  Any objects referenced by those statics will be
   * transitively included in the boot image.
   *
   * This is the entry point for all build-time activity in the collector.
   */
  //public static final void staticinit() throws VM_PragmaInterruptible {
  // VM_Interface.init();
  //}

  /**
   * Initialization that occurs at <i>boot</i> time (runtime
   * initialization).  This is only executed by one processor (the
   * primordial thread).
   */
  public static final void staticboot (int heapsize)
    throws VM_PragmaInterruptible {
    runningVM = true;
    HeapGrowthManager.boot(heapsize, heapsize);
    Util.boot();
    Plan.boot();
    VMResource.boot();
    //Statistics.boot();
    Monitor.boot();
  }

  public static boolean runningVM;

  /**
   * Sets up the fields of a <code>VM_Processor</code> object to
   * accommodate allocation and garbage collection running on that processor.
   * This may involve creating a remset array or a buffer for GC tracing.
   * 
   * This method is called from the constructor of VM_Processor. For the
   * PRIMORDIAL processor, which is allocated while the bootimage is being
   * built, this method is called a second time, from VM.boot, when the 
   * VM is starting.
   *
   * @param p The <code>VM_Processor</code> object.
   *
  public static final void setupProcessor(VM_Processor proc)
    throws VM_PragmaInterruptible {
    // if (proc.mmPlan == null) proc.mmPlan = new Plan();
    // if (VM.VerifyAssertions) VM._assert(proc.mmPlan != null);
  }
  */
  /**
   * Perform postBoot operations such as dealing with command line
   * options (this is called as soon as options have been parsed,
   * which is necessarily after the basic allocator boot).
   */
  public static void postBoot() throws VM_PragmaInterruptible {
    Plan.postBoot();
  }

  /** 
   *  Process GC parameters.
   */
  public static void processCommandLineArg(String arg)
    throws VM_PragmaInterruptible {
    //    Options.process(arg);
    throw new UnimplementedException("processCommandLineArg");
  }

  /***********************************************************************
   *
   * Write barriers
   */

  /**
   * Write barrier for putfield operations.
   *
   * @param ref the object which is the subject of the putfield
   * @param offset the offset of the field to be modified
   * @param value the new value for the field
   */
  public static void putfieldWriteBarrier(CoreServicesAccess _,
					  Object ref, int offset, Object value)
    throws VM_PragmaInline {
    VM_Interface.getPlan().putFieldWriteBarrier(
                                   VM_Magic.objectAsAddress(ref), offset,
				   VM_Magic.objectAsAddress(value));
  }
  
  /**
   * Write barrier for putstatic operations.
   *
   * @param ref the object which is the subject of the putfield
   * @param offset the offset of the field to be modified
   * @param value the new value for the field
  public static void putstaticWriteBarrier(int offset, Object value)
    throws VM_PragmaInline { 
    // putstatic barrier currently unimplemented
   //TODO: if (VM.VerifyAssertions) VM._assert(false);
    //     VM_Address jtocSlot = VM_Magic.objectAsAddress(VM_Magic.getJTOC()).add(offset);
    //     VM_Interface.getPlan().putStaticWriteBarrier(jtocSlot, VM_Magic.objectAsAddress(value));
  }
   */

  /**
   * Take appropriate write barrier actions for the creation of a new
   * reference by an aastore bytecode.
   *
   * @param ref the array containing the source of the new reference.
   * @param index the index into the array were the new referece
   * resides.  The index is the "natural" index into the array, for
   * example a[index].
   * @param value the object that is the target of the new reference.
   */
  public static void arrayStoreWriteBarrier(CoreServicesAccess _,
					    Object ref, int index,
					    Object value)
    throws VM_PragmaInline {
    VM_Interface.getPlan().arrayStoreWriteBarrier(
				     VM_Magic.objectAsAddress(ref), index,
				     VM_Magic.objectAsAddress(value));
  }

  /**
   * Checks that if a garbage collection is in progress then the given
   * object is not movable.  If it is movable error messages are
   * logged and the system exits.
   *
   * @param obj the object to check
   */
  public static void modifyCheck(Object obj) {
    /* Make sure we don't GC does not putField on a possible moving
     * object. */
    if (Plan.gcInProgressProper()) {
	VM_Address ref = VM_Magic.objectAsAddress(obj);
	if (VMResource.refIsMovable(ref)) {
//TODO:	    VM.sysWriteln("GC modifying a potentially moving object via Java (i.e. not magic)");
//	    VM.sysWriteln("  obj = ", ref);
//	    VM_Type t = VM_Magic.getObjectType(obj);
//	    VM.sysWrite(" type = "); VM.sysWriteln(t.getDescriptor());
	    //VM.sysFail("GC modifying a potentially moving object via Java (i.e. not magic)");
	}
    }
  }

  /***********************************************************************
   *
   * Statistics
   */
  
  /**
   * Returns the number of collections that have occured.
   *
   * @return The number of collections that have occured.
   */
  public static final int getCollectionCount()
    throws VM_PragmaUninterruptible {
    return 0 ; // TODO: VM_CollectorThread.collectionCount;
  }
  

  /***********************************************************************
   *
   * Application interface to memory manager
   */
  
  /**
   * Returns the amount of free memory.
   *
   * @return The amount of free memory.
   */
  public static final long freeMemory() {
    return Plan.freeMemory();
  }

  /**
   * Returns the amount of total memory.
   *
   * @return The amount of total memory.
   */
  public static final long totalMemory() {
    return Plan.totalMemory();
  }

  /**
   * Returns the maximum amount of memory VM will attempt to use.
   *
   * @return The maximum amount of memory VM will attempt to use.
   */
  public static final long maxMemory() {
    return HeapGrowthManager.getMaxHeapSize();
  }

  public void doGC() {
    gc();
  }

  /**
   * External call to force a garbage collection.
   */
  public static final void gc() throws VM_PragmaInterruptible {
    //Statistics.gcExternalCount++;
    //if (!Options.ignoreSystemGC)
    VM_Interface.triggerCollection(VM_Interface.EXTERNAL_GC_TRIGGER);
  }

  /****************************************************************************
   *
   * Check references, log information about references
   */

  /**
   * Logs information about a reference to the error output.
   *
   * @param ref the address to log information about
   */
  public static void dumpRef(VM_Address ref) throws VM_PragmaUninterruptible {
    Util.dumpRef(ref);
  }

  /**
   * Checks if a reference is valid.
   *
   * @param ref the address to be checked
   * @return <code>true</code> if the reference is valid
   */
  public static boolean validRef(VM_Address ref)
    throws VM_PragmaUninterruptible, VM_PragmaInline {
    return Util.validRef(ref);
  }

  /**
   * Checks if an address refers to an in-use area of memory.
   * 
   * @param address the address to be checked
   * @return <code>true</code> if the address refers to an in use area
   */
  public static boolean addrInVM(VM_Address address)
    throws VM_PragmaUninterruptible, VM_PragmaInline {
    return VMResource.addrInVM(address);
  }

  /**
   * Checks if a reference refers to an object in an in-use area of
   * memory.
   *
   * <p>References may be addresses just outside the memory region
   * allocated to the object.
   *
   * @param ref the reference to be checked
   * @return <code>true</code> if the object refered to is in an
   * in-use area
   */
  public static boolean refInVM(VM_Address ref)
    throws VM_PragmaUninterruptible, VM_PragmaInline {
    return VMResource.refInVM(ref);
  }

  /***********************************************************************
   *
   * Allocation
   */

  /**
   * Returns the appropriate allocation scheme/area for the given
   * type.  This form is deprecated.  Without the VM_Method argument,
   * it is possible that the wrong allocator is chosen which may
   * affect correctness. The prototypical example is that JMTk
   * meta-data must generally be in immortal or at least non-moving
   * space.
   *
   *
   * @param type the type of the object to be allocated
   * @return the identifier of the appropriate allocator
   *
  public static int pickAllocator(VM_Type type) throws VM_PragmaInterruptible {
      return pickAllocator(type, null);
  }
  */
 /**
   * Is string <code>a</code> a prefix of string
   * <code>b</code>. String <code>b</code> is encoded as an ASCII byte
   * array.
   *
   * @param a prefix string
   * @param b string which may contain prefix, encoded as an ASCII
   * byte array.
   * @return <code>true</code> if <code>a</code> is a prefix of
   * <code>b</code>
   */
  private static boolean isPrefix(String a, byte [] b)
    throws VM_PragmaInterruptible {
    int aLen = a.length();
    if (aLen > b.length)
      return false;
    for (int i = 0; i<aLen; i++) {
      if (a.charAt(i) != ((char) b[i]))
	return false;
    }
    return true;
  }

  /**
   * Returns the appropriate allocation scheme/area for the given type
   * and given method requesting the allocation.
   * 
   * @param type the type of the object to be allocated
   * @param method the method requesting the allocation
   * @return the identifier of the appropriate allocator
   */
//   public static int pickAllocator(VM_Type type, VM_Method method)
//     throws VM_PragmaInterruptible {
//     /*
//      * First we chcek the calling method so GC-data can go into
//      * special places.  Then we cache the result of the allocator
//      * assuming that it is type-based only.  A better implementation
//      * would be call-site specific which is strictly more refined.
//      */
//     if (method != null) {
//      // We should strive to be allocation-free here.
//       VM_Class cls = method.getDeclaringClass();
//       byte[] clsBA = cls.getDescriptor().toByteArray();
//       if (isPrefix("Lcom/ibm/JikesRVM/memoryManagers/JMTk/", clsBA)) {
// 	return Plan.IMMORTAL_SPACE;
//       }
//     }
//     Type t = type.JMTKtype;
//     if (t.initialized)
//       return t.allocator;
//     int allocator = Plan.DEFAULT_SPACE;
//     byte[] typeBA = type.getDescriptor().toByteArray();
//     if (isPrefix("Lcom/ibm/JikesRVM/memoryManagers/", typeBA) ||
// 	isPrefix("Lcom/ibm/JikesRVM/VM_Processor;", typeBA) ||
// 	isPrefix("Lcom/ibm/JikesRVM/jni/VM_JNIEnvironment;", typeBA))
//       allocator = Plan.IMMORTAL_SPACE;
//     t.initialized = true;
//     t.allocator = allocator;
//     return allocator;
//   }

  /*
   * These methods allocate memory in JMTk, we implement the OVM's set of 3
   * allocation routines instead.
   */

//   /**
//    * Allocate a scalar object.
//    *
//    * @param size Size in bytes of the object, including any headers
//    * that need space.
//    * @param tib  Type of the object (pointer to TIB).
//    * @param allocator Specify which allocation scheme/area JMTk should
//    * allocate the memory from.
//    * @return the initialized Object
//    */
//   public static Oop allocateScalar(int size, Object [] tib, Blueprint.Scalar bp,
// 				   int allocator) 
//     throws VM_PragmaUninterruptible, VM_PragmaInline {
//     if((size & (~(BYTES_IN_ADDRESS-1))) != size){
//       size = ((size & (~(BYTES_IN_ADDRESS-1))) + BYTES_IN_ADDRESS);
//     }
//   }

//   public static Oop clone(Oop oop, Blueprint bp, Object[] tib, int allocator){
//   }

//   /**
//    * Allocate an array object.
//    * 
//    * @param numElements number of array elements
//    * @param logElementSize size in bytes of an array element, log base 2.
//    * @param headerSize size in bytes of array header
//    * @param tib type information block for array object
//    * @param allocator int that encodes which allocator should be used
//    * @return array object with header installed and all elements set 
//    *         to zero/null
//    * See also: bytecode 0xbc ("newarray") and 0xbd ("anewarray")
//    */ 
//   public static Oop allocateArray(int numElements, Object[] tib, Blueprint.Array bp,
// 				     int allocator)
//     throws VM_PragmaUninterruptible, VM_PragmaInline {
//     Plan plan = VM_Interface.getPlan();
//     int size = bp.computeSizeFor(numElements);
    
//     if((size & (~(BYTES_IN_ADDRESS-1))) != size){
//       size = ((size & (~(BYTES_IN_ADDRESS-1))) + BYTES_IN_ADDRESS);
//     }
//     AllocAdvice advice = plan.getAllocAdvice(null, size, null, null);
//     VM_Address region = plan.alloc(size, false, allocator, advice);
//     if (CHECK_MEMORY_IS_ZEROED) Memory.assertIsZeroed(region, size);
//     Oop result = bp.stamp(region, numElements);
//     plan.postAlloc(VM_Address.fromObject(result), tib, size, false,
// 		   allocator);
//     return result;
//   }

  /**
   * Allocate an array object, using the given array as an example of
   * the required type.
   *
   * @param array an array of the type to be allocated
   * @param allocator which allocation scheme/area JMTk should
   * allocation the memory from.
   * @param length the number of elements in the array to be allocated
   * @return the initialzed array object
   */
  public static Object cloneArray(Object [] array, int allocator, int length)
      throws VM_PragmaUninterruptible {
    Blueprint.Array arrbp = (Blueprint.Array)VM_Address.fromObject(array).asOop().getBlueprint();
    Oop ret = MemoryManager.the().allocateArray(arrbp, length);
    return VM_Address.fromObject(ret);
  }


  /***********************************************************************
   *
   * Specialized allocation routines
   */

  /**
   * Allocate a VM_CodeArray
   * NOTE: We don't use this at all for Jikes RVM right now.
   *       It might be useful to think about expanding the interface
   *       to take hints on the likely hot/coldness of the code and
   *       other code placement hints.
   * @param n The number of instructions to allocate
   * @return The  array
   *
  public static VM_CodeArray newInstructions(int n)
    throws VM_PragmaInline, VM_PragmaInterruptible {
    return VM_CodeArray.create(n);
  }
  */
  /**
   * Allocate a stack array
   * @param n The number of stack slots to allocate
   * @return The stack array
   */ 
  public static int[] newStack(int n)
    throws VM_PragmaInline, VM_PragmaInterruptible {
    return new int[n];
  }

  /**
   * Allocate an aligned stack array that will live forever and does not move
   * @param n The number of stack slots to allocate
   * @return The stack array
   */ 
  public static int[] newImmortalStack(int n) throws VM_PragmaInterruptible {
    throw new UnimplementedException("newImmortalStack");
  }

  /**
   * Allocate a contiguous VM_CompiledMethod array
   * @param n The number of objects
   * @return The contiguous object array
   * 
  public static VM_CompiledMethod[] newContiguousCompiledMethodArray(int n)
    throws VM_PragmaInline, VM_PragmaInterruptible {
    return new VM_CompiledMethod[n];
  }
  */
  /**
   * Allocate a contiguous VM_DynamicLibrary array
   * @param n The number of objects
   * @return The contiguous object array
   *
  public static VM_DynamicLibrary[] newContiguousDynamicLibraryArray(int n)
    throws VM_PragmaInline, VM_PragmaInterruptible {
    return new VM_DynamicLibrary[n];
  }
  */
  /**
   * Allocate a new type information block (TIB).
   *
   * @param n the number of slots in the TIB to be allocated
   * @return the new TIB
   *
  public static Object[] newTIB (int n)
    throws VM_PragmaInline, VM_PragmaInterruptible {
    if (VM.runningVM) {
      VM_Array objectArrayType = VM_Type.JavaLangObjectArrayType;
      Object [] objectArrayTib = objectArrayType.getTypeInformationBlock();
      Object result = allocateArray(n, objectArrayType.getLogElementSize(),
				    VM_ObjectModel.computeArrayHeaderSize(objectArrayType),
				    objectArrayTib, Plan.IMMORTAL_SPACE);
      return (Object []) result;
    } else
      return new Object[n];
  }
  */

  /***********************************************************************
   *
   * Finalizers
   */
  
  /**
   * Adds an object to the list of objects to have their
   * <code>finalize</code> method called when they are reclaimed.
   *
   * @param obj the object to be added to the finalizer's list
   */
  public static void addFinalizer(Object obj) throws VM_PragmaInterruptible {
    throw new UnimplementedException("addFinalizer");
    //Finalizer.addCandidate(obj);
  }

  /**
   * Gets an object from the list of objects that are to be reclaimed
   * and need to have their <code>finalize</code> method called.
   *
   * @return the object needing to be finialized
   */
  public static Object getFinalizedObject() throws VM_PragmaInterruptible {
    throw new UnimplementedException("getFinalizedObject");
    //    return Finalizer.get();
  }


  /***********************************************************************
   *
   * References
   */

  /**
   * Add a soft reference to the list of soft references.
   *
   * @param obj the soft reference to be added to the list
   */
/*
 * 
  public static void addSoftReference(SoftReference obj)
     throws VM_PragmaInterruptible {
     ReferenceProcessor.addSoftCandidate(obj);
   }
 */
  
  /**
   * Add a weak reference to the list of weak references.
   *
   * @param obj the weak reference to be added to the list
   */
/*
    public static void addWeakReference(WeakReference obj)
     throws VM_PragmaInterruptible {
     ReferenceProcessor.addWeakCandidate(obj);
   }
*/ 
  /**
   * Add a phantom reference to the list of phantom references.
   *
   * @param obj the phantom reference to be added to the list
   */
 /*  public static void addPhantomReference(PhantomReference obj)
     throws VM_PragmaInterruptible {
     ReferenceProcessor.addPhantomCandidate(obj);
   }
*/

  /***********************************************************************
   *
   * Tracing
   */

  /**
   * Processes an object during the tracing phase of a collection.
   *
   * @param obj the address of the object to be processed
   */
  public static VM_Address processPtrValue(VM_Address obj)
    throws VM_PragmaUninterruptible, VM_PragmaInline { 
    return Plan.traceObject(obj);
  }

  public static Oop processOopValue(Oop oop)
    throws VM_PragmaUninterruptible, VM_PragmaInline {
    return Plan.traceObject(VM_Address.fromObject(oop)).asOop();
  }

  /**
   * Processes an object during the tracing phase of a collection.
   *
   * @param location the address of a reference to the object to be
   * processed
   */
  public static void processPtrLocation(VM_Address location)
    throws VM_PragmaUninterruptible, VM_PragmaInline { 
    Plan.traceObjectLocation(location, false);
  }

  /***********************************************************************
   *
   * Heap size and heap growth
   */

  /**
   * Return the max heap size in bytes (as set by -Xmx).
   *
   * @return The max heap size in bytes (as set by -Xmx).
   */
  public static int getMaxHeapSize() {
    return HeapGrowthManager.getMaxHeapSize();
  }

  /**
   * Return the initial heap size in bytes (as set by -Xms).
   *
   * @return The initial heap size in bytes (as set by -Xms).
   */
  public static int getInitialHeapSize() {
    return HeapGrowthManager.getInitialHeapSize();
  }

  /**
   * Increase heap size for an emergency, such as processing an out of
   * memory exception.
   * 
   * @param growSize number of bytes to increase the heap size
   */
  public static void emergencyGrowHeap(int growSize) { // in bytes
    // This can be undoable if the current thread doesn't cause 'em
    // all to exit.
    // if (VM.VerifyAssertions && growSize < 0) VM._assert(false);
    HeapGrowthManager.overrideGrowHeapSize(growSize);
  }

  
 /***********************************************************************
  *
  * Miscellaneous
  */

  /**
   * Generic hook to allow benchmarks to be harnessed.  A plan may use
   * this to perform certain actions prior to the commencement of a
   * benchmark, such as a full heap collection, turning on
   * instrumentation, etc.
   */
  public static void harnessBegin() {
    Plan.harnessBegin();
  }

  /**
   * Generic hook to allow benchmarks to be harnessed.  A plan may use
   * this to perform certain actions after the completion of a
   * benchmark, such as a full heap collection, turning off
   * instrumentation, etc.
   */
  public static void harnessEnd() {
    Plan.harnessEnd();
  }

  /**
   * Check if object might be a TIB.
   *
   * @param obj address of object to check
   * @return <code>false</code> if the object is in the wrong
   * allocation scheme/area for a TIB, <code>true</code> otherwise
   */
  public static boolean mightBeTIB (VM_Address obj)
    throws VM_PragmaInline, VM_PragmaUninterruptible {
    return VMResource.refIsImmortal(obj);
  }

  /**
   * Returns true if GC is in progress.
   *
   * @return True if GC is in progress.
   */
  public static final boolean gcInProgress() throws VM_PragmaUninterruptible {
    return Plan.gcInProgress();
  }


 /***********************************************************************
  *
  * Deprecated and/or broken.  The following need to be expunged.
  */

  /**
   * Returns the maximum number of heaps that can be managed.
   *
   * @return the maximum number of heaps
   */
  public static int getMaxHeaps() {
    /*
     *  The boot record has a table of address ranges of the heaps,
     *  the maximum number of heaps is used to size the table.
     */
    return VMResource.getMaxVMResource();
  }

   /**
    * Allocate an immortal short array that will live forever and does not move
    * @param n The number of elements
    * @return The short array
    */ 
   public static short[] newImmortalShortArray (int n)
     throws VM_PragmaInterruptible {
     throw new UnimplementedException("newImmortalShortArray");
   }

  /**
   * Allocate a contiguous int array
   * @param n The number of ints
   * @return The contiguous int array
   */ 
  public static int[] newContiguousIntArray(int n)
    throws VM_PragmaInline, VM_PragmaInterruptible {
    return new int[n];
  }

  /**************
   * OVM specific. Since the stitcher needs a singleton to implement the 
   * MemoryManager class, we use a constructor to call the build-time 
   * init method, and a boot method to call the required boot method. The
   * remaining functions dispatch to the most relevant JMTk method
   */

  int heapsize;

  public MM_Interface(String heapSize){
    heapsize = CommandLine.parseSize(heapSize);
  }

  //public void init(){
  //  staticinit();
  //}

  public void boot(){
    staticboot(heapsize);
  }

  public void fullyBootedVM(){
    super.fullyBootedVM();
    Plan.fullyBooted();
    Lock.fullyBooted();
  }

  // Are ALL JMTk configurations precise?
  public boolean isPrecise() { return true; }

  public Oop allocate(Blueprint.Scalar bp) throws PragmaAtomic {
    int size = bp.getFixedSize();
    Plan plan = VM_Interface.getPlan();
    AllocAdvice advice = plan.getAllocAdvice(null, size, null, null);
    VM_Address region = plan.alloc(size, true, Plan.DEFAULT_SPACE, advice);
    if (CHECK_MEMORY_IS_ZEROED) Memory.assertIsZeroed(region, size);
    Oop result = bp.stamp(region);
    plan.postAlloc(VM_Address.fromObject(result), null, size, true,
		   Plan.DEFAULT_SPACE);
    return result;
  }

  public Oop allocateArray(Blueprint.Array bp, int len) throws PragmaAtomic {
    long _size = bp.computeSizeFor(len);
    if (_size < Integer.MAX_VALUE) {
      int size = (int) _size;
      Plan plan = VM_Interface.getPlan();
      AllocAdvice advice = plan.getAllocAdvice(null, size, null, null);
      VM_Address region = plan.alloc(size, false, Plan.DEFAULT_SPACE, advice);
      if (CHECK_MEMORY_IS_ZEROED) Memory.assertIsZeroed(region, size);
      Oop result = bp.stamp(region, len);
      plan.postAlloc(VM_Address.fromObject(result), null, size, false,
		     Plan.DEFAULT_SPACE);
      return result;
    }
    else
	throw outOfMemory();
  }

  // FIXME: should check whether we are cloning a scalar or array,
  // however, cloneArray() is incomplete
  public Oop clone(Oop oop) throws PragmaAtomic {
    Plan plan = VM_Interface.getPlan();
    Blueprint bp = oop.getBlueprint();
    int size = bp.getVariableSize(oop);
    boolean isScalar = bp instanceof Blueprint.Scalar;
    AllocAdvice advice = plan.getAllocAdvice(null, size, null, null);
    VM_Address region = plan.alloc(size, isScalar, Plan.DEFAULT_SPACE, advice);
    if (CHECK_MEMORY_IS_ZEROED) Memory.assertIsZeroed(region, size);
    Oop result = bp.clone(oop, region);
    plan.postAlloc(VM_Address.fromObject(result), null, size, isScalar,
		   Plan.DEFAULT_SPACE);
    return result;
  }

  public VM_Address getMem(int size) {
    throw new UnimplementedException("getMem");
  }
  
  public boolean needsWriteBarrier() {
    return VM_Interface.getPlan().NEEDS_WRITE_BARRIER;
  }
  
  public void putFieldBarrier(CoreServicesAccess csa,
			      Oop src, int offset, Oop tgt) {
    VM_Interface.getPlan().writeBarrier(src, offset, tgt, csa);
  }
  
  public void aastoreBarrier(CoreServicesAccess csa,
			     Oop src, int offset, Oop tgt) {
    VM_Interface.getPlan().writeBarrier(src, offset, tgt, csa);
  }

  public VM_Area setCurrentArea(VM_Area a) {
    return VM_Interface.getPlan().setCurrentArea((MemoryArea)a);
  }

  public VM_Area getHeapArea() {
    return MemoryArea.getHeapArea();
  }
  
  public VM_Area getImmortalArea() {
    return MemoryArea.getImmortalArea();
  }

  public VM_Area getCurrentArea() {
    return VM_Interface.getPlan().getCurrentArea();
  }

  public VM_Area areaOf(Oop oop) {
    return VM_Interface.getPlan().areaOf(VM_Address.fromObject(oop));
  }
  
  public VM_Area makeExplicitArea(int size) {
    return new MemoryArea(null, size);
  }

  public VM_Area makeScopedArea(Oop mirror, int size) {
    return new MemoryArea(mirror, size);
  }
  
  public boolean supportsGC() { return true; }

  public void garbageCollect() throws PragmaAtomic {
    VM_Interface.triggerCollection(VM_Interface.EXTERNAL_GC_TRIGGER);
  }
  
}
