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