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