001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.mm.mminterface;
014
015import static org.jikesrvm.HeapLayoutConstants.BOOT_IMAGE_CODE_SIZE;
016import static org.jikesrvm.HeapLayoutConstants.BOOT_IMAGE_CODE_START;
017import static org.jikesrvm.HeapLayoutConstants.BOOT_IMAGE_DATA_SIZE;
018import static org.jikesrvm.HeapLayoutConstants.BOOT_IMAGE_DATA_START;
019import static org.jikesrvm.objectmodel.TIBLayoutConstants.IMT_METHOD_SLOTS;
020import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG;
021import static org.mmtk.utility.Constants.MIN_ALIGNMENT;
022
023import java.lang.ref.PhantomReference;
024import java.lang.ref.SoftReference;
025import java.lang.ref.WeakReference;
026
027import org.jikesrvm.VM;
028import org.jikesrvm.classloader.RVMArray;
029import org.jikesrvm.classloader.RVMClass;
030import org.jikesrvm.classloader.RVMMethod;
031import org.jikesrvm.classloader.RVMType;
032import org.jikesrvm.classloader.SpecializedMethod;
033import org.jikesrvm.classloader.TypeReference;
034import org.jikesrvm.compilers.common.CodeArray;
035import org.jikesrvm.mm.mmtk.FinalizableProcessor;
036import org.jikesrvm.mm.mmtk.ReferenceProcessor;
037import org.jikesrvm.mm.mmtk.SynchronizedCounter;
038import org.jikesrvm.objectmodel.BootImageInterface;
039import org.jikesrvm.objectmodel.IMT;
040import org.jikesrvm.objectmodel.ITable;
041import org.jikesrvm.objectmodel.ITableArray;
042import org.jikesrvm.objectmodel.JavaHeader;
043import org.jikesrvm.objectmodel.ObjectModel;
044import org.jikesrvm.objectmodel.TIB;
045import org.jikesrvm.options.OptionSet;
046import org.jikesrvm.runtime.BootRecord;
047import org.jikesrvm.runtime.Callbacks;
048import org.jikesrvm.runtime.Magic;
049import org.mmtk.plan.CollectorContext;
050import org.mmtk.plan.Plan;
051import org.mmtk.policy.Space;
052import org.mmtk.utility.Memory;
053import org.mmtk.utility.alloc.Allocator;
054import org.mmtk.utility.gcspy.GCspy;
055import org.mmtk.utility.heap.HeapGrowthManager;
056import org.mmtk.utility.heap.Mmapper;
057import org.mmtk.utility.options.Options;
058import org.vmmagic.pragma.Entrypoint;
059import org.vmmagic.pragma.Inline;
060import org.vmmagic.pragma.Interruptible;
061import org.vmmagic.pragma.NoInline;
062import org.vmmagic.pragma.Pure;
063import org.vmmagic.pragma.Uninterruptible;
064import org.vmmagic.pragma.Unpreemptible;
065import org.vmmagic.pragma.UnpreemptibleNoWarn;
066import org.vmmagic.unboxed.Address;
067import org.vmmagic.unboxed.Extent;
068import org.vmmagic.unboxed.ObjectReference;
069import org.vmmagic.unboxed.Offset;
070import org.vmmagic.unboxed.Word;
071import org.vmmagic.unboxed.WordArray;
072
073/**
074 * The interface that the MMTk memory manager presents to Jikes RVM
075 */
076@Uninterruptible
077public final class MemoryManager {
078
079  /***********************************************************************
080   *
081   * Class variables
082   */
083
084  /**
085   * <code>true</code> if checking of allocated memory to ensure it is
086   * zeroed is desired.
087   */
088  private static final boolean CHECK_MEMORY_IS_ZEROED = false;
089  private static final boolean traceAllocator = false;
090
091  /**
092   * Has the interface been booted yet?
093   */
094  private static boolean booted = false;
095
096  /**
097   * Has garbage collection been enabled yet?
098   */
099  private static boolean collectionEnabled = false;
100
101  /***********************************************************************
102   *
103   * Initialization
104   */
105
106  /**
107   * Suppress default constructor to enforce noninstantiability.
108   */
109  private MemoryManager() {} // This constructor will never be invoked.
110
111  /**
112   * Initialization that occurs at <i>boot</i> time (runtime
113   * initialization).  This is only executed by one processor (the
114   * primordial thread).
115   * @param theBootRecord the boot record. Contains information about
116   * the heap size.
117   */
118  @Interruptible
119  public static void boot(BootRecord theBootRecord) {
120    Extent pageSize = BootRecord.the_boot_record.bytesInPage;
121    org.jikesrvm.runtime.Memory.setPageSize(pageSize);
122    Mmapper.markAsMapped(BOOT_IMAGE_DATA_START, BOOT_IMAGE_DATA_SIZE);
123    Mmapper.markAsMapped(BOOT_IMAGE_CODE_START, BOOT_IMAGE_CODE_SIZE);
124    HeapGrowthManager.boot(theBootRecord.initialHeapSize, theBootRecord.maximumHeapSize);
125    DebugUtil.boot(theBootRecord);
126    Selected.Plan.get().enableAllocation();
127    SynchronizedCounter.boot();
128
129    Callbacks.addExitMonitor(new Callbacks.ExitMonitor() {
130      @Override
131      public void notifyExit(int value) {
132        Selected.Plan.get().notifyExit(value);
133      }
134    });
135
136    booted = true;
137  }
138
139  /**
140   * Perform postBoot operations such as dealing with command line
141   * options (this is called as soon as options have been parsed,
142   * which is necessarily after the basic allocator boot).
143   */
144  @Interruptible
145  public static void postBoot() {
146    Selected.Plan.get().processOptions();
147
148    if (Options.noReferenceTypes.getValue()) {
149      RVMType.JavaLangRefReferenceReferenceField.makeTraced();
150    }
151
152    if (VM.BuildWithGCSpy) {
153      // start the GCSpy interpreter server
154      MemoryManager.startGCspyServer();
155    }
156  }
157
158  /**
159   * Allow collection (assumes threads can be created).
160   */
161  @Interruptible
162  public static void enableCollection() {
163    Selected.Plan.get().enableCollection();
164    collectionEnabled = true;
165  }
166
167  /**
168   * @return whether collection is enabled
169   */
170  public static boolean collectionEnabled() {
171    return collectionEnabled;
172  }
173
174  /**
175   * Notify the MM that the host VM is now fully booted.
176   */
177  @Interruptible
178  public static void fullyBootedVM() {
179    Selected.Plan.get().fullyBooted();
180  }
181
182  @Interruptible
183  public static void processCommandLineArg(String arg) {
184    if (!OptionSet.gc.process(arg)) {
185      VM.sysWriteln("Unrecognized command line argument: \"" + arg + "\"");
186      VM.sysExit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
187    }
188  }
189
190  /***********************************************************************
191   *
192   * Write barriers
193   */
194
195  /**
196   * Checks that if a garbage collection is in progress then the given
197   * object is not movable.  If it is movable error messages are
198   * logged and the system exits.
199   *
200   * @param object the object to check
201   */
202  @Entrypoint
203  public static void modifyCheck(Object object) {
204    /* Make sure that during GC, we don't update on a possibly moving object.
205       Such updates are dangerous because they can be lost.
206     */
207    if (Plan.gcInProgressProper()) {
208      ObjectReference ref = ObjectReference.fromObject(object);
209      if (Space.isMovable(ref)) {
210        VM.sysWriteln("GC modifying a potentially moving object via Java (i.e. not magic)");
211        VM.sysWriteln("  obj = ", ref);
212        RVMType t = Magic.getObjectType(object);
213        VM.sysWrite(" type = ");
214        VM.sysWriteln(t.getDescriptor());
215        VM.sysFail("GC modifying a potentially moving object via Java (i.e. not magic)");
216      }
217    }
218  }
219
220  /***********************************************************************
221   *
222   * Statistics
223   */
224
225  /***********************************************************************
226   *
227   * Application interface to memory manager
228   */
229
230  /**
231   * Returns the amount of free memory.
232   *
233   * @return The amount of free memory.
234   */
235  public static Extent freeMemory() {
236    return Plan.freeMemory();
237  }
238
239  /**
240   * Returns the amount of total memory.
241   *
242   * @return The amount of total memory.
243   */
244  public static Extent totalMemory() {
245    return Plan.totalMemory();
246  }
247
248  /**
249   * Returns the maximum amount of memory VM will attempt to use.
250   *
251   * @return The maximum amount of memory VM will attempt to use.
252   */
253  public static Extent maxMemory() {
254    return HeapGrowthManager.getMaxHeapSize();
255  }
256
257  /**
258   * External call to force a garbage collection.
259   */
260  @Interruptible
261  public static void gc() {
262    Selected.Plan.handleUserCollectionRequest();
263  }
264
265  /****************************************************************************
266   *
267   * Check references, log information about references
268   */
269
270  /**
271   * Logs information about a reference to the error output.
272   *
273   * @param ref the address to log information about
274   */
275  public static void dumpRef(ObjectReference ref) {
276    DebugUtil.dumpRef(ref);
277  }
278
279  /**
280   * Checks if a reference is valid.
281   *
282   * @param ref the address to be checked
283   * @return <code>true</code> if the reference is valid
284   */
285  @Inline
286  public static boolean validRef(ObjectReference ref) {
287    if (booted) {
288      return DebugUtil.validRef(ref);
289    } else {
290      return true;
291    }
292  }
293
294  /**
295   * Checks if an address refers to an in-use area of memory.
296   *
297   * @param address the address to be checked
298   * @return <code>true</code> if the address refers to an in use area
299   */
300  @Inline
301  public static boolean addressInVM(Address address) {
302    return Space.isMappedAddress(address);
303  }
304
305  /**
306   * Checks if a reference refers to an object in an in-use area of
307   * memory.
308   *
309   * <p>References may be addresses just outside the memory region
310   * allocated to the object.
311   *
312   * @param object the reference to be checked
313   * @return <code>true</code> if the object refered to is in an
314   * in-use area
315   */
316  @Inline
317  public static boolean objectInVM(ObjectReference object) {
318    return Space.isMappedObject(object);
319  }
320
321  /**
322   * Return true if address is in a space which may contain stacks
323   *
324   * @param address The address to be checked
325   * @return true if the address is within a space which may contain stacks
326   */
327  public static boolean mightBeFP(Address address) {
328    // In general we don't know which spaces may hold allocated stacks.
329    // If we want to be more specific than the space being mapped we
330    // will need to add a check in Plan that can be overriden.
331    return Space.isMappedAddress(address);
332  }
333  /***********************************************************************
334   *
335   * Allocation
336   */
337
338  /**
339   * Return an allocation site upon request.  The request may be made
340   * in the context of compilation.
341   *
342   * @param compileTime {@code true} if this request is being made in the
343   * context of a compilation.
344   * @return an allocation site
345   */
346  public static int getAllocationSite(boolean compileTime) {
347    return Plan.getAllocationSite(compileTime);
348  }
349
350  /**
351   * Returns the appropriate allocation scheme/area for the given
352   * type.  This form is deprecated.  Without the RVMMethod argument,
353   * it is possible that the wrong allocator is chosen which may
354   * affect correctness. The prototypical example is that JMTk
355   * meta-data must generally be in immortal or at least non-moving
356   * space.
357   *
358   *
359   * @param type the type of the object to be allocated
360   * @return the identifier of the appropriate allocator
361   */
362  @Interruptible
363  public static int pickAllocator(RVMType type) {
364    return pickAllocator(type, null);
365  }
366
367  /**
368   * Is string <code>a</code> a prefix of string
369   * <code>b</code>. String <code>b</code> is encoded as an ASCII byte
370   * array.
371   *
372   * @param a prefix string
373   * @param b string which may contain prefix, encoded as an ASCII
374   * byte array.
375   * @return <code>true</code> if <code>a</code> is a prefix of
376   * <code>b</code>
377   */
378  @Interruptible
379  private static boolean isPrefix(String a, byte[] b) {
380    int aLen = a.length();
381    if (aLen > b.length) {
382      return false;
383    }
384    for (int i = 0; i < aLen; i++) {
385      if (a.charAt(i) != ((char) b[i])) {
386        return false;
387      }
388    }
389    return true;
390  }
391
392  /**
393   * Returns the appropriate allocation scheme/area for the given type
394   * and given method requesting the allocation.
395   *
396   * @param type the type of the object to be allocated
397   * @param method the method requesting the allocation
398   * @return the identifier of the appropriate allocator
399   */
400  @Interruptible
401  public static int pickAllocator(RVMType type, RVMMethod method) {
402    if (traceAllocator) {
403      VM.sysWrite("allocator for ");
404      VM.sysWrite(type.getDescriptor());
405      VM.sysWrite(": ");
406    }
407    if (method != null) {
408      // We should strive to be allocation-free here.
409      RVMClass cls = method.getDeclaringClass();
410      byte[] clsBA = cls.getDescriptor().toByteArray();
411      if (Selected.Constraints.get().withGCspy()) {
412        if (isPrefix("Lorg/mmtk/vm/gcspy/", clsBA) || isPrefix("[Lorg/mmtk/vm/gcspy/", clsBA)) {
413          if (traceAllocator) {
414            VM.sysWriteln("GCSPY");
415          }
416          return Plan.ALLOC_GCSPY;
417        }
418      }
419      if (isPrefix("Lorg/jikesrvm/mm/mmtk/ReferenceProcessor", clsBA)) {
420        if (traceAllocator) {
421          VM.sysWriteln("DEFAULT");
422        }
423        return Plan.ALLOC_DEFAULT;
424      }
425      if (isPrefix("Lorg/mmtk/", clsBA) || isPrefix("Lorg/jikesrvm/mm/", clsBA)) {
426        if (traceAllocator) {
427          VM.sysWriteln("NONMOVING");
428        }
429        return Plan.ALLOC_NON_MOVING;
430      }
431      if (method.isNonMovingAllocation()) {
432        return Plan.ALLOC_NON_MOVING;
433      }
434    }
435    if (traceAllocator) {
436      VM.sysWriteln(type.getMMAllocator());
437    }
438    return type.getMMAllocator();
439  }
440
441  /**
442   * Determine the default allocator to be used for a given type.
443   *
444   * @param type The type in question
445   * @return The allocator to use for allocating instances of type
446   * <code>type</code>.
447   */
448  @Interruptible
449  private static int pickAllocatorForType(RVMType type) {
450    int allocator = Plan.ALLOC_DEFAULT;
451    if (type.isArrayType()) {
452      RVMType elementType = type.asArray().getElementType();
453      if (elementType.isPrimitiveType() || elementType.isUnboxedType()) {
454        allocator = Plan.ALLOC_NON_REFERENCE;
455      }
456    }
457    if (type.isNonMoving()) {
458      allocator = Plan.ALLOC_NON_MOVING;
459    }
460    byte[] typeBA = type.getDescriptor().toByteArray();
461    if (Selected.Constraints.get().withGCspy()) {
462      if (isPrefix("Lorg/mmtk/vm/gcspy/", typeBA) || isPrefix("[Lorg/mmtk/vm/gcspy/", typeBA)) {
463        allocator = Plan.ALLOC_GCSPY;
464      }
465    }
466    if (isPrefix("Lorg/jikesrvm/tuningfork", typeBA) || isPrefix("[Lorg/jikesrvm/tuningfork", typeBA) ||
467        isPrefix("Lcom/ibm/tuningfork/", typeBA) || isPrefix("[Lcom/ibm/tuningfork/", typeBA) ||
468        isPrefix("Lorg/mmtk/", typeBA) || isPrefix("[Lorg/mmtk/", typeBA) ||
469        isPrefix("Lorg/jikesrvm/mm/", typeBA) || isPrefix("[Lorg/jikesrvm/mm/", typeBA) ||
470        isPrefix("Lorg/jikesrvm/jni/JNIEnvironment;", typeBA)) {
471      allocator = Plan.ALLOC_NON_MOVING;
472    }
473    return allocator;
474  }
475
476  /***********************************************************************
477   * These methods allocate memory.  Specialized versions are available for
478   * particular object types.
479   ***********************************************************************
480   */
481
482  /**
483   * Allocate a scalar object.
484   *
485   * @param size Size in bytes of the object, including any headers
486   * that need space.
487   * @param tib  Type of the object (pointer to TIB).
488   * @param allocator Specify which allocation scheme/area JMTk should
489   * allocate the memory from.
490   * @param align the alignment requested; must be a power of 2.
491   * @param offset the offset at which the alignment is desired.
492   * @param site allocation site.
493   * @return the initialized Object
494   */
495  @Inline
496  public static Object allocateScalar(int size, TIB tib, int allocator, int align, int offset, int site) {
497    Selected.Mutator mutator = Selected.Mutator.get();
498    allocator = mutator.checkAllocator(org.jikesrvm.runtime.Memory.alignUp(size, MIN_ALIGNMENT), align, allocator);
499    Address region = allocateSpace(mutator, size, align, offset, allocator, site);
500    Object result = ObjectModel.initializeScalar(region, tib, size);
501    mutator.postAlloc(ObjectReference.fromObject(result), ObjectReference.fromObject(tib), size, allocator);
502    return result;
503  }
504
505  /**
506   * Allocate an array object. This is the interruptible component, including throwing
507   * an OutOfMemoryError for arrays that are too large.
508   *
509   * @param numElements number of array elements
510   * @param logElementSize size in bytes of an array element, log base 2.
511   * @param headerSize size in bytes of array header
512   * @param tib type information block for array object
513   * @param allocator int that encodes which allocator should be used
514   * @param align the alignment requested; must be a power of 2.
515   * @param offset the offset at which the alignment is desired.
516   * @param site allocation site.
517   * @return array object with header installed and all elements set
518   *         to zero/null
519   * See also: bytecode 0xbc ("newarray") and 0xbd ("anewarray")
520   */
521  @Inline
522  @Unpreemptible
523  public static Object allocateArray(int numElements, int logElementSize, int headerSize, TIB tib, int allocator,
524                                     int align, int offset, int site) {
525    int elemBytes = numElements << logElementSize;
526    if ((elemBytes >>> logElementSize) != numElements) {
527      /* asked to allocate more than Integer.MAX_VALUE bytes */
528      throwLargeArrayOutOfMemoryError();
529    }
530    int size = elemBytes + headerSize;
531    return allocateArrayInternal(numElements, size, tib, allocator, align, offset, site);
532  }
533
534
535  /**
536   * Throw an out of memory error due to an array allocation request that is
537   * larger than the maximum allowed value. This is in a separate method
538   * so it can be forced out of line.
539   */
540  @NoInline
541  @UnpreemptibleNoWarn
542  private static void throwLargeArrayOutOfMemoryError() {
543    throw new OutOfMemoryError();
544  }
545
546  /**
547   * Allocate an array object.
548   *
549   * @param numElements The number of element bytes
550   * @param size size in bytes of array header
551   * @param tib type information block for array object
552   * @param allocator int that encodes which allocator should be used
553   * @param align the alignment requested; must be a power of 2.
554   * @param offset the offset at which the alignment is desired.
555   * @param site allocation site.
556   * @return array object with header installed and all elements set
557   *         to zero/{@code null}
558   * See also: bytecode 0xbc ("newarray") and 0xbd ("anewarray")
559   */
560  @Inline
561  private static Object allocateArrayInternal(int numElements, int size, TIB tib, int allocator,
562                                              int align, int offset, int site) {
563    Selected.Mutator mutator = Selected.Mutator.get();
564    allocator = mutator.checkAllocator(org.jikesrvm.runtime.Memory.alignUp(size, MIN_ALIGNMENT), align, allocator);
565    Address region = allocateSpace(mutator, size, align, offset, allocator, site);
566    Object result = ObjectModel.initializeArray(region, tib, numElements, size);
567    mutator.postAlloc(ObjectReference.fromObject(result), ObjectReference.fromObject(tib), size, allocator);
568    return result;
569  }
570
571  /**
572   * Allocate space for runtime allocation of an object
573   *
574   * @param mutator The mutator instance to be used for this allocation
575   * @param bytes The size of the allocation in bytes
576   * @param align The alignment requested; must be a power of 2.
577   * @param offset The offset at which the alignment is desired.
578   * @param allocator The MMTk allocator to be used (if allocating)
579   * @param site Allocation site.
580   * @return The first byte of a suitably sized and aligned region of memory.
581   */
582  @Inline
583  private static Address allocateSpace(Selected.Mutator mutator, int bytes, int align, int offset, int allocator,
584                                       int site) {
585    /* MMTk requests must be in multiples of MIN_ALIGNMENT */
586    bytes = org.jikesrvm.runtime.Memory.alignUp(bytes, MIN_ALIGNMENT);
587
588    /* Now make the request */
589    Address region;
590    region = mutator.alloc(bytes, align, offset, allocator, site);
591
592    /* TODO: if (Stats.GATHER_MARK_CONS_STATS) Plan.cons.inc(bytes); */
593    if (CHECK_MEMORY_IS_ZEROED) Memory.assertIsZeroed(region, bytes);
594
595    return region;
596  }
597
598  /**
599   * Allocate space for GC-time copying of an object
600   *
601   * @param context The collector context to be used for this allocation
602   * @param bytes The size of the allocation in bytes
603   * @param allocator the allocator associated with this request
604   * @param align The alignment requested; must be a power of 2.
605   * @param offset The offset at which the alignment is desired.
606   * @param from The source object from which this is to be copied
607   * @return The first byte of a suitably sized and aligned region of memory.
608   */
609  @Inline
610  public static Address allocateSpace(CollectorContext context, int bytes, int align, int offset, int allocator,
611                                      ObjectReference from) {
612    /* MMTk requests must be in multiples of MIN_ALIGNMENT */
613    bytes = org.jikesrvm.runtime.Memory.alignUp(bytes, MIN_ALIGNMENT);
614
615    /* Now make the request */
616    Address region;
617    region = context.allocCopy(from, bytes, align, offset, allocator);
618
619    /* TODO: if (Stats.GATHER_MARK_CONS_STATS) Plan.mark.inc(bytes); */
620    if (CHECK_MEMORY_IS_ZEROED) Memory.assertIsZeroed(region, bytes);
621
622    return region;
623  }
624
625  /**
626   * Align an allocation using some modulo arithmetic to guarantee the
627   * following property:<br>
628   * <code>(region + offset) % alignment == 0</code>
629   *
630   * @param initialOffset The initial (unaligned) start value of the
631   * allocated region of memory.
632   * @param align The alignment requested, must be a power of two
633   * @param offset The offset at which the alignment is desired
634   * @return <code>initialOffset</code> plus some delta (possibly 0) such
635   * that the return value is aligned according to the above
636   * constraints.
637   */
638  @Inline
639  public static Offset alignAllocation(Offset initialOffset, int align, int offset) {
640    Address region = org.jikesrvm.runtime.Memory.alignUp(initialOffset.toWord().toAddress(), MIN_ALIGNMENT);
641    return Allocator.alignAllocationNoFill(region, align, offset).toWord().toOffset();
642  }
643
644  /**
645   * Allocate a CodeArray into a code space.
646   * Currently the interface is fairly primitive;
647   * just the number of instructions in the code array and a boolean
648   * to indicate hot or cold code.
649   * @param numInstrs number of instructions
650   * @param isHot is this a request for hot code space allocation?
651   * @return The  array
652   */
653  @NoInline
654  @Interruptible
655  public static CodeArray allocateCode(int numInstrs, boolean isHot) {
656    RVMArray type = RVMType.CodeArrayType;
657    int headerSize = ObjectModel.computeArrayHeaderSize(type);
658    int align = ObjectModel.getAlignment(type);
659    int offset = ObjectModel.getOffsetForAlignment(type, false);
660    int width = type.getLogElementSize();
661    TIB tib = type.getTypeInformationBlock();
662    int allocator = isHot ? Plan.ALLOC_HOT_CODE : Plan.ALLOC_COLD_CODE;
663
664    return (CodeArray) allocateArray(numInstrs, width, headerSize, tib, allocator, align, offset, Plan.DEFAULT_SITE);
665  }
666
667  /**
668   * Allocate a stack
669   * @param bytes    The number of bytes to allocate
670   * @return The stack
671   */
672  @NoInline
673  @Unpreemptible
674  public static byte[] newStack(int bytes) {
675    if (!VM.runningVM) {
676      return new byte[bytes];
677    } else {
678      RVMArray stackType = RVMArray.ByteArray;
679      int headerSize = ObjectModel.computeArrayHeaderSize(stackType);
680      int align = ObjectModel.getAlignment(stackType);
681      int offset = ObjectModel.getOffsetForAlignment(stackType, false);
682      int width = stackType.getLogElementSize();
683      TIB stackTib = stackType.getTypeInformationBlock();
684
685      return (byte[]) allocateArray(bytes,
686                                    width,
687                                    headerSize,
688                                    stackTib,
689                                    Plan.ALLOC_STACK,
690                                    align,
691                                    offset,
692                                    Plan.DEFAULT_SITE);
693    }
694  }
695
696  /**
697   * Allocates a non moving word array.
698   *
699   * @param size The size of the array
700   * @return the new non moving word array
701   */
702  @NoInline
703  @Interruptible
704  public static WordArray newNonMovingWordArray(int size) {
705    if (!VM.runningVM) {
706      return WordArray.create(size);
707    }
708
709    RVMArray arrayType = RVMType.WordArrayType;
710    int headerSize = ObjectModel.computeArrayHeaderSize(arrayType);
711    int align = ObjectModel.getAlignment(arrayType);
712    int offset = ObjectModel.getOffsetForAlignment(arrayType, false);
713    int width = arrayType.getLogElementSize();
714    TIB arrayTib = arrayType.getTypeInformationBlock();
715
716    return (WordArray) allocateArray(size,
717                                 width,
718                                 headerSize,
719                                 arrayTib,
720                                 Plan.ALLOC_NON_MOVING,
721                                 align,
722                                 offset,
723                                 Plan.DEFAULT_SITE);
724
725  }
726
727  /**
728   * Allocates a non moving double array.
729   *
730   * @param size The size of the array
731   * @return the new non moving double array
732   */
733  @NoInline
734  @Interruptible
735  public static double[] newNonMovingDoubleArray(int size) {
736    if (!VM.runningVM) {
737      return new double[size];
738    }
739
740    RVMArray arrayType = RVMArray.DoubleArray;
741    int headerSize = ObjectModel.computeArrayHeaderSize(arrayType);
742    int align = ObjectModel.getAlignment(arrayType);
743    int offset = ObjectModel.getOffsetForAlignment(arrayType, false);
744    int width = arrayType.getLogElementSize();
745    TIB arrayTib = arrayType.getTypeInformationBlock();
746
747    return (double[]) allocateArray(size,
748                                 width,
749                                 headerSize,
750                                 arrayTib,
751                                 Plan.ALLOC_NON_MOVING,
752                                 align,
753                                 offset,
754                                 Plan.DEFAULT_SITE);
755
756  }
757
758  /**
759   * Allocates a non moving int array.
760   *
761   * @param size The size of the array
762   * @return the new non moving int array
763   */
764  @NoInline
765  @Interruptible
766  public static int[] newNonMovingIntArray(int size) {
767    if (!VM.runningVM) {
768      return new int[size];
769    }
770
771    RVMArray arrayType = RVMArray.IntArray;
772    int headerSize = ObjectModel.computeArrayHeaderSize(arrayType);
773    int align = ObjectModel.getAlignment(arrayType);
774    int offset = ObjectModel.getOffsetForAlignment(arrayType, false);
775    int width = arrayType.getLogElementSize();
776    TIB arrayTib = arrayType.getTypeInformationBlock();
777
778    return (int[]) allocateArray(size,
779                                 width,
780                                 headerSize,
781                                 arrayTib,
782                                 Plan.ALLOC_NON_MOVING,
783                                 align,
784                                 offset,
785                                 Plan.DEFAULT_SITE);
786
787  }
788
789  /**
790   * Allocates a non moving short array.
791   *
792   * @param size The size of the array
793   * @return the new non moving short array
794   */
795  @NoInline
796  @Interruptible
797  public static short[] newNonMovingShortArray(int size) {
798    if (!VM.runningVM) {
799      return new short[size];
800    }
801
802    RVMArray arrayType = RVMArray.ShortArray;
803    int headerSize = ObjectModel.computeArrayHeaderSize(arrayType);
804    int align = ObjectModel.getAlignment(arrayType);
805    int offset = ObjectModel.getOffsetForAlignment(arrayType, false);
806    int width = arrayType.getLogElementSize();
807    TIB arrayTib = arrayType.getTypeInformationBlock();
808
809    return (short[]) allocateArray(size,
810                                 width,
811                                 headerSize,
812                                 arrayTib,
813                                 Plan.ALLOC_NON_MOVING,
814                                 align,
815                                 offset,
816                                 Plan.DEFAULT_SITE);
817
818  }
819
820  /**
821   * Allocates a new type information block (TIB).
822   *
823   * @param numVirtualMethods the number of virtual method slots in the TIB
824   * @param alignCode alignment encoding for the TIB
825   * @return the new TIB
826   * @see AlignmentEncoding
827   */
828  @NoInline
829  @Interruptible
830  public static TIB newTIB(int numVirtualMethods, int alignCode) {
831    int elements = TIB.computeSize(numVirtualMethods);
832
833    if (!VM.runningVM) {
834      return TIB.allocate(elements, alignCode);
835    }
836    if (alignCode == AlignmentEncoding.ALIGN_CODE_NONE) {
837      return (TIB)newRuntimeTable(elements, RVMType.TIBType);
838    }
839
840    RVMType type = RVMType.TIBType;
841    if (VM.VerifyAssertions) VM._assert(VM.runningVM);
842
843    TIB realTib = type.getTypeInformationBlock();
844    RVMArray fakeType = RVMType.WordArrayType;
845    TIB fakeTib = fakeType.getTypeInformationBlock();
846    int headerSize = ObjectModel.computeArrayHeaderSize(fakeType);
847    int align = ObjectModel.getAlignment(fakeType);
848    int offset = ObjectModel.getOffsetForAlignment(fakeType, false);
849    int width = fakeType.getLogElementSize();
850    int elemBytes = elements << width;
851    if ((elemBytes >>> width) != elements) {
852      /* asked to allocate more than Integer.MAX_VALUE bytes */
853      throwLargeArrayOutOfMemoryError();
854    }
855    int size = elemBytes + headerSize + AlignmentEncoding.padding(alignCode);
856    Selected.Mutator mutator = Selected.Mutator.get();
857    Address region = allocateSpace(mutator, size, align, offset, type.getMMAllocator(), Plan.DEFAULT_SITE);
858
859    region = AlignmentEncoding.adjustRegion(alignCode, region);
860
861    Object result = ObjectModel.initializeArray(region, fakeTib, elements, size);
862    mutator.postAlloc(ObjectReference.fromObject(result), ObjectReference.fromObject(fakeTib), size, type.getMMAllocator());
863
864    /* Now we replace the TIB */
865    ObjectModel.setTIB(result, realTib);
866
867    return (TIB)result;
868  }
869
870  /**
871   * Allocate a new interface method table (IMT).
872   *
873   * @return the new IMT
874   */
875  @NoInline
876  @Interruptible
877  public static IMT newIMT() {
878    if (!VM.runningVM) {
879      return IMT.allocate();
880    }
881
882    return (IMT)newRuntimeTable(IMT_METHOD_SLOTS, RVMType.IMTType);
883  }
884
885  /**
886   * Allocate a new ITable
887   *
888   * @param size the number of slots in the ITable
889   * @return the new ITable
890   */
891  @NoInline
892  @Interruptible
893  public static ITable newITable(int size) {
894    if (!VM.runningVM) {
895      return ITable.allocate(size);
896    }
897
898    return (ITable)newRuntimeTable(size, RVMType.ITableType);
899  }
900
901  /**
902   * Allocate a new ITableArray
903   *
904   * @param size the number of slots in the ITableArray
905   * @return the new ITableArray
906   */
907  @NoInline
908  @Interruptible
909  public static ITableArray newITableArray(int size) {
910    if (!VM.runningVM) {
911      return ITableArray.allocate(size);
912    }
913
914    return (ITableArray)newRuntimeTable(size, RVMType.ITableArrayType);
915  }
916
917  /**
918   * Allocates a new runtime table (at runtime).
919   *
920   * @param size The size of the table
921   * @param type the type for the table
922   * @return the newly allocated table
923   */
924  @NoInline
925  @Interruptible
926  public static Object newRuntimeTable(int size, RVMType type) {
927    if (VM.VerifyAssertions) VM._assert(VM.runningVM);
928
929    TIB realTib = type.getTypeInformationBlock();
930    RVMArray fakeType = RVMType.WordArrayType;
931    TIB fakeTib = fakeType.getTypeInformationBlock();
932    int headerSize = ObjectModel.computeArrayHeaderSize(fakeType);
933    int align = ObjectModel.getAlignment(fakeType);
934    int offset = ObjectModel.getOffsetForAlignment(fakeType, false);
935    int width = fakeType.getLogElementSize();
936
937    /* Allocate a word array */
938    Object array = allocateArray(size,
939                                 width,
940                                 headerSize,
941                                 fakeTib,
942                                 type.getMMAllocator(),
943                                 align,
944                                 offset,
945                                 Plan.DEFAULT_SITE);
946
947    /* Now we replace the TIB */
948    ObjectModel.setTIB(array, realTib);
949    return array;
950  }
951
952  /**
953   * Checks if the object can move. This information is useful to
954   *  optimize some JNI calls.
955   *
956   * @param obj the object in question
957   * @return {@code true} if this object can never move, {@code false}
958   *   if it can move.
959   */
960  @Pure
961  public static boolean willNeverMove(Object obj) {
962    return Selected.Plan.get().willNeverMove(ObjectReference.fromObject(obj));
963  }
964
965  /**
966   * @param obj the object in question
967   * @return whether the object is immortal
968   */
969  @Pure
970  public static boolean isImmortal(Object obj) {
971    return Space.isImmortal(ObjectReference.fromObject(obj));
972  }
973
974  /***********************************************************************
975   *
976   * Finalizers
977   */
978
979  /**
980   * Adds an object to the list of objects to have their
981   * <code>finalize</code> method called when they are reclaimed.
982   *
983   * @param object the object to be added to the finalizer's list
984   */
985  @Interruptible
986  public static void addFinalizer(Object object) {
987    FinalizableProcessor.addCandidate(object);
988  }
989
990  /**
991   * Gets an object from the list of objects that are to be reclaimed
992   * and need to have their <code>finalize</code> method called.
993   *
994   * @return the object needing to be finialized
995   */
996  @Unpreemptible("Non-preemptible but may yield if finalizable table is being grown")
997  public static Object getFinalizedObject() {
998    return FinalizableProcessor.getForFinalize();
999  }
1000
1001  /***********************************************************************
1002   *
1003   * References
1004   */
1005
1006  /**
1007   * Add a soft reference to the list of soft references.
1008   *
1009   * @param obj the soft reference to be added to the list
1010   * @param referent the object that the reference points to
1011   */
1012  @Interruptible
1013  public static void addSoftReference(SoftReference<?> obj, Object referent) {
1014    ReferenceProcessor.addSoftCandidate(obj,ObjectReference.fromObject(referent));
1015  }
1016
1017  /**
1018   * Add a weak reference to the list of weak references.
1019   *
1020   * @param obj the weak reference to be added to the list
1021   * @param referent the object that the reference points to
1022   */
1023  @Interruptible
1024  public static void addWeakReference(WeakReference<?> obj, Object referent) {
1025    ReferenceProcessor.addWeakCandidate(obj,ObjectReference.fromObject(referent));
1026  }
1027
1028  /**
1029   * Add a phantom reference to the list of phantom references.
1030   *
1031   * @param obj the phantom reference to be added to the list
1032   * @param referent the object that the reference points to
1033   */
1034  @Interruptible
1035  public static void addPhantomReference(PhantomReference<?> obj, Object referent) {
1036    ReferenceProcessor.addPhantomCandidate(obj,ObjectReference.fromObject(referent));
1037  }
1038
1039  /***********************************************************************
1040   *
1041   * Tracing
1042   */
1043
1044  /***********************************************************************
1045   *
1046   * Heap size and heap growth
1047   */
1048
1049  /**
1050   * Return the max heap size in bytes (as set by -Xmx).
1051   *
1052   * @return The max heap size in bytes (as set by -Xmx).
1053   */
1054  public static Extent getMaxHeapSize() {
1055    return HeapGrowthManager.getMaxHeapSize();
1056  }
1057
1058  /***********************************************************************
1059   *
1060   * Miscellaneous
1061   */
1062
1063  /**
1064   * A new type has been resolved by the VM.  Create a new MM type to
1065   * reflect the VM type, and associate the MM type with the VM type.
1066   *
1067   * @param vmType The newly resolved type
1068   */
1069  @Interruptible
1070  public static void notifyClassResolved(RVMType vmType) {
1071    vmType.setMMAllocator(pickAllocatorForType(vmType));
1072  }
1073
1074  /**
1075   * Check if object might be a TIB.
1076   *
1077   * @param obj address of object to check
1078   * @return <code>false</code> if the object is in the wrong
1079   * allocation scheme/area for a TIB, <code>true</code> otherwise
1080   */
1081  @Inline
1082  public static boolean mightBeTIB(ObjectReference obj) {
1083    return !obj.isNull() &&
1084           Space.isMappedObject(obj) &&
1085           Space.isMappedObject(ObjectReference.fromObject(ObjectModel.getTIB(obj)));
1086  }
1087
1088  /**
1089   * Returns true if GC is in progress.
1090   *
1091   * @return True if GC is in progress.
1092   */
1093  public static boolean gcInProgress() {
1094    return Plan.gcInProgress();
1095  }
1096
1097  /**
1098   * Start the GCspy server
1099   */
1100  @Interruptible
1101  public static void startGCspyServer() {
1102    GCspy.startGCspyServer();
1103  }
1104
1105  /**
1106   * Flush the mutator context.
1107   */
1108  public static void flushMutatorContext() {
1109    Selected.Mutator.get().flush();
1110  }
1111
1112  /**
1113   * @return the number of specialized methods.
1114   */
1115  public static int numSpecializedMethods() {
1116    return SpecializedScanMethod.ENABLED ? Selected.Constraints.get().numSpecializedScans() : 0;
1117  }
1118
1119  /**
1120   * Initialize a specified specialized method.
1121   *
1122   * @param id the specializedMethod
1123   * @return the created specialized scan method
1124   */
1125  @Interruptible
1126  public static SpecializedMethod createSpecializedMethod(int id) {
1127    if (VM.VerifyAssertions) {
1128      VM._assert(SpecializedScanMethod.ENABLED);
1129      VM._assert(id < Selected.Constraints.get().numSpecializedScans());
1130    }
1131
1132    /* What does the plan want us to specialize this to? */
1133    Class<?> traceClass = Selected.Plan.get().getSpecializedScanClass(id);
1134
1135    /* Create the specialized method */
1136    return new SpecializedScanMethod(id, TypeReference.findOrCreate(traceClass));
1137  }
1138
1139  /***********************************************************************
1140   *
1141   * Header initialization
1142   */
1143
1144  /**
1145   * Override the boot-time initialization method here, so that
1146   * the core MMTk code doesn't need to know about the
1147   * BootImageInterface type.
1148   *
1149   * @param bootImage the bootimage instance
1150   * @param ref the object's address
1151   * @param tib the object's TIB
1152   * @param size the number of bytes allocated by the GC system for
1153   *  the object
1154   * @param isScalar whether the header belongs to a scalar or an array
1155   */
1156  @Interruptible
1157  public static void initializeHeader(BootImageInterface bootImage, Address ref, TIB tib, int size,
1158                                      boolean isScalar) {
1159    //    int status = JavaHeader.readAvailableBitsWord(bootImage, ref);
1160    byte status = Selected.Plan.get().setBuildTimeGCByte(ref, ObjectReference.fromObject(tib), size);
1161    JavaHeader.writeAvailableByte(bootImage, ref, status);
1162  }
1163
1164  /**
1165   * Installs a reference into the boot image.
1166   *
1167   * @param value the reference to install
1168   * @return the installed reference
1169   */
1170  @Interruptible
1171  public static Word bootTimeWriteBarrier(Word value) {
1172    return Selected.Plan.get().bootTimeWriteBarrier(value);
1173  }
1174
1175  /***********************************************************************
1176   *
1177   * Deprecated and/or broken.  The following need to be expunged.
1178   */
1179
1180  /**
1181   * Returns the maximum number of heaps that can be managed.
1182   *
1183   * @return the maximum number of heaps
1184   */
1185  public static int getMaxHeaps() {
1186    /*
1187     *  The boot record has a table of address ranges of the heaps,
1188     *  the maximum number of heaps is used to size the table.
1189     */
1190    return Space.MAX_SPACES;
1191  }
1192
1193  /**
1194   * Allocate a contiguous int array
1195   * @param n The number of ints
1196   * @return The contiguous int array
1197   */
1198  @Inline
1199  @Interruptible
1200  public static int[] newContiguousIntArray(int n) {
1201    return new int[n];
1202  }
1203
1204}
1205