/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.memorymanagers.mminterface; import java.lang.ref.PhantomReference; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import org.jikesrvm.ArchitectureSpecific.VM_CodeArray; import org.jikesrvm.VM; import org.jikesrvm.VM_HeapLayoutConstants; import org.jikesrvm.classloader.VM_Array; import org.jikesrvm.classloader.VM_Class; import org.jikesrvm.classloader.VM_Method; import org.jikesrvm.classloader.VM_SpecializedMethod; import org.jikesrvm.classloader.VM_Type; import org.jikesrvm.classloader.VM_TypeReference; import org.jikesrvm.compilers.common.VM_CompiledMethod; import org.jikesrvm.mm.mmtk.Collection; import org.jikesrvm.mm.mmtk.Options; import org.jikesrvm.mm.mmtk.ReferenceProcessor; import org.jikesrvm.mm.mmtk.SynchronizedCounter; import org.jikesrvm.objectmodel.BootImageInterface; import org.jikesrvm.objectmodel.VM_JavaHeader; import org.jikesrvm.objectmodel.VM_ObjectModel; import org.jikesrvm.runtime.VM_BootRecord; import org.jikesrvm.runtime.VM_Magic; import org.jikesrvm.runtime.VM_Memory; import org.mmtk.plan.Plan; import org.mmtk.policy.Space; import org.mmtk.utility.Constants; import org.mmtk.utility.Finalizer; import org.mmtk.utility.Memory; import org.mmtk.utility.alloc.Allocator; import org.mmtk.utility.gcspy.GCspy; import org.mmtk.utility.heap.HeapGrowthManager; import org.mmtk.utility.heap.Mmapper; import org.vmmagic.pragma.Entrypoint; import org.vmmagic.pragma.Inline; import org.vmmagic.pragma.Interruptible; import org.vmmagic.pragma.NoInline; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Extent; import org.vmmagic.unboxed.ObjectReference; import org.vmmagic.unboxed.Offset; import org.vmmagic.unboxed.Word; /** * The interface that the JMTk memory manager presents to the Jikes * research virtual machine. */ @Uninterruptible public final class MM_Interface implements VM_HeapLayoutConstants, Constants { /*********************************************************************** * * Class variables */ /** * <code>true</code> if checking of allocated memory to ensure it is * zeroed is desired. */ private static final boolean CHECK_MEMORY_IS_ZEROED = false; /*********************************************************************** * * Initialization */ /** * Suppress default constructor to enforce noninstantiability. */ private MM_Interface() {} // This constructor will never be invoked. /** * Initialization that occurs at <i>build</i> time. The value of * statics as at the completion of this routine will be reflected in * the boot image. Any objects referenced by those statics will be * transitively included in the boot image. * * This is the entry point for all build-time activity in the collector. */ @Interruptible public static void init() { VM_CollectorThread.init(); VM_ConcurrentCollectorThread.init(); org.jikesrvm.mm.mmtk.Collection.init(); } /** * Initialization that occurs at <i>boot</i> time (runtime * initialization). This is only executed by one processor (the * primordial thread). * @param theBootRecord the boot record. Contains information about * the heap size. */ @Interruptible public static void boot(VM_BootRecord theBootRecord) { Mmapper.markAsMapped(BOOT_IMAGE_DATA_START, BOOT_IMAGE_DATA_SIZE); Mmapper.markAsMapped(BOOT_IMAGE_CODE_START, BOOT_IMAGE_CODE_SIZE); HeapGrowthManager.boot(theBootRecord.initialHeapSize, theBootRecord.maximumHeapSize); DebugUtil.boot(theBootRecord); Selected.Plan.get().boot(); SynchronizedCounter.boot(); Monitor.boot(); } /** * Perform postBoot operations such as dealing with command line * options (this is called as soon as options have been parsed, * which is necessarily after the basic allocator boot). */ @Interruptible public static void postBoot() { Selected.Plan.get().postBoot(); if (VM.BuildWithGCSpy) { // start the GCSpy interpreter server MM_Interface.startGCspyServer(); } } /** * Notify the MM that the host VM is now fully booted. */ @Interruptible public static void fullyBootedVM() { Selected.Plan.get().fullyBooted(); } /** * Process GC parameters. */ @Interruptible public static void processCommandLineArg(String arg) { if (!Options.process(arg)) { VM.sysWriteln("Unrecognized command line argument: \"" + arg + "\""); VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); } } /*********************************************************************** * * Write barriers */ /** * Write barrier for putfield operations. * * @param ref the object which is the subject of the putfield * @param offset the offset of the field to be modified * @param value the new value for the field * @param locationMetadata an int that encodes the source location being modified */ @Inline @Entrypoint public static void putfieldWriteBarrier(Object ref, Offset offset, Object value, int locationMetadata) { ObjectReference src = ObjectReference.fromObject(ref); Selected.Mutator.get().writeBarrier(src, src.toAddress().plus(offset), ObjectReference.fromObject(value), offset, locationMetadata, PUTFIELD_WRITE_BARRIER); } /** * Write barrier for compare and exchange object field operations. * * @param ref the object which is the subject of the putfield * @param offset the offset of the field to be modified * @param old the old value to swap out * @param value the new value for the field */ @Inline public static boolean tryCompareAndSwapWriteBarrier(Object ref, Offset offset, Object old, Object value) { ObjectReference src = ObjectReference.fromObject(ref); return Selected.Mutator.get().tryCompareAndSwapWriteBarrier(src, src.toAddress().plus(offset), ObjectReference.fromObject(old), ObjectReference.fromObject(value), offset, 0, // do not have location metadata PUTFIELD_WRITE_BARRIER); } /** * Write barrier for putstatic operations. * * @param offset the offset of the field to be modified * @param value the new value for the field * @param locationMetadata an int that encodes the source location being modified */ @Inline @Entrypoint public static void putstaticWriteBarrier(Offset offset, Object value, int locationMetadata) { ObjectReference src = ObjectReference.fromObject(VM_Magic.getJTOC()); Selected.Mutator.get().writeBarrier(src, src.toAddress().plus(offset), ObjectReference.fromObject(value), offset, locationMetadata, PUTSTATIC_WRITE_BARRIER); } /** * Take appropriate write barrier actions for the creation of a new * reference by an aastore bytecode. * * @param ref the array containing the source of the new reference. * @param index the index into the array were the new referece * resides. The index is the "natural" index into the array, for * example a[index]. * @param value the object that is the target of the new reference. */ @Inline @Entrypoint public static void arrayStoreWriteBarrier(Object ref, int index, Object value) { ObjectReference array = ObjectReference.fromObject(ref); Offset offset = Offset.fromIntZeroExtend(index << LOG_BYTES_IN_ADDRESS); Selected.Mutator.get().writeBarrier(array, array.toAddress().plus(offset), ObjectReference.fromObject(value), offset, 0, // don't know metadata AASTORE_WRITE_BARRIER); } /** * Take appropriate write barrier actions when a series of * references are copied (i.e. in an array copy). * * @param src The source object * @param srcOffset The offset of the first source address, in * bytes, relative to <code>src</code> (in principle, this could be * negative). * @param tgt The target object * @param tgtOffset The offset of the first target address, in bytes * relative to <code>tgt</code> (in principle, this could be * negative). * @param bytes The size of the region being copied, in bytes. * @return True if the update was performed by the barrier, false if * left to the caller (always false in this case). */ @Inline public static boolean arrayCopyWriteBarrier(Object src, Offset srcOffset, Object tgt, Offset tgtOffset, int bytes) { return Selected.Mutator.get().writeBarrier(ObjectReference.fromObject(src), srcOffset, ObjectReference.fromObject(tgt), tgtOffset, bytes); } /*********************************************************************** * * Read barriers */ /** * A reference type is being read. * * @param obj The non-null referent about to be released to the mutator. * @return The object to release to the mutator. */ public static Object referenceTypeReadBarrier(Object obj) { ObjectReference result = Selected.Mutator.get().referenceTypeReadBarrier(ObjectReference.fromObject(obj)); return result.toObject(); } /** * Checks that if a garbage collection is in progress then the given * object is not movable. If it is movable error messages are * logged and the system exits. * * @param object the object to check */ @Entrypoint public static void modifyCheck(Object object) { /* Make sure that during GC, we don't update on a possibly moving object. Such updates are dangerous because they can be lost. */ if (Plan.gcInProgressProper()) { ObjectReference ref = ObjectReference.fromObject(object); if (Space.isMovable(ref)) { VM.sysWriteln("GC modifying a potentially moving object via Java (i.e. not magic)"); VM.sysWriteln(" obj = ", ref); VM_Type t = VM_Magic.getObjectType(object); VM.sysWrite(" type = "); VM.sysWriteln(t.getDescriptor()); VM.sysFail("GC modifying a potentially moving object via Java (i.e. not magic)"); } } } /*********************************************************************** * * Statistics */ /** * Returns the number of collections that have occured. * * @return The number of collections that have occured. */ public static int getCollectionCount() { return VM_CollectorThread.collectionCount; } /*********************************************************************** * * Application interface to memory manager */ /** * Returns the amount of free memory. * * @return The amount of free memory. */ public static Extent freeMemory() { return Plan.freeMemory(); } /** * Returns the amount of total memory. * * @return The amount of total memory. */ public static Extent totalMemory() { return Plan.totalMemory(); } /** * Returns the maximum amount of memory VM will attempt to use. * * @return The maximum amount of memory VM will attempt to use. */ public static Extent maxMemory() { return HeapGrowthManager.getMaxHeapSize(); } /** * External call to force a garbage collection. */ @Interruptible public static void gc() { if (!org.mmtk.utility.options.Options.ignoreSystemGC.getValue()) { Collection.triggerCollectionStatic(Collection.EXTERNAL_GC_TRIGGER); } } /**************************************************************************** * * Check references, log information about references */ /** * Logs information about a reference to the error output. * * @param ref the address to log information about */ public static void dumpRef(ObjectReference ref) { DebugUtil.dumpRef(ref); } /** * Checks if a reference is valid. * * @param ref the address to be checked * @return <code>true</code> if the reference is valid */ @Inline public static boolean validRef(ObjectReference ref) { return DebugUtil.validRef(ref); } /** * Checks if an address refers to an in-use area of memory. * * @param address the address to be checked * @return <code>true</code> if the address refers to an in use area */ @Inline public static boolean addressInVM(Address address) { return Space.isMappedAddress(address); } /** * Checks if a reference refers to an object in an in-use area of * memory. * * <p>References may be addresses just outside the memory region * allocated to the object. * * @param object the reference to be checked * @return <code>true</code> if the object refered to is in an * in-use area */ @Inline public static boolean objectInVM(ObjectReference object) { return Space.isMappedObject(object); } /** * Return true if address is in a space which may contain stacks * * @param address The address to be checked * @return true if the address is within a space which may contain stacks */ public static boolean mightBeFP(Address address) { return Space.isInSpace(Plan.LOS, address) || Space.isInSpace(Plan.IMMORTAL, address) || Space.isInSpace(Plan.VM_SPACE, address); } /*********************************************************************** * * Allocation */ /** * Return an allocation site upon request. The request may be made * in the context of compilation. * * @param compileTime True if this request is being made in the * context of a compilation. * @return an allocation site */ public static int getAllocationSite(boolean compileTime) { return Plan.getAllocationSite(compileTime); } /** * Returns the appropriate allocation scheme/area for the given * type. This form is deprecated. Without the VM_Method argument, * it is possible that the wrong allocator is chosen which may * affect correctness. The prototypical example is that JMTk * meta-data must generally be in immortal or at least non-moving * space. * * * @param type the type of the object to be allocated * @return the identifier of the appropriate allocator */ @Interruptible public static int pickAllocator(VM_Type type) { return pickAllocator(type, null); } /** * Is string <code>a</code> a prefix of string * <code>b</code>. String <code>b</code> is encoded as an ASCII byte * array. * * @param a prefix string * @param b string which may contain prefix, encoded as an ASCII * byte array. * @return <code>true</code> if <code>a</code> is a prefix of * <code>b</code> */ @Interruptible private static boolean isPrefix(String a, byte[] b) { int aLen = a.length(); if (aLen > b.length) { return false; } for (int i = 0; i < aLen; i++) { if (a.charAt(i) != ((char) b[i])) { return false; } } return true; } /** * Returns the appropriate allocation scheme/area for the given type * and given method requesting the allocation. * * @param type the type of the object to be allocated * @param method the method requesting the allocation * @return the identifier of the appropriate allocator */ @Interruptible public static int pickAllocator(VM_Type type, VM_Method method) { if (method != null) { // We should strive to be allocation-free here. VM_Class cls = method.getDeclaringClass(); byte[] clsBA = cls.getDescriptor().toByteArray(); if (Selected.Constraints.get().withGCspy()) { if (isPrefix("Lorg/mmtk/vm/gcspy/", clsBA) || isPrefix("[Lorg/mmtk/vm/gcspy/", clsBA)) { return Plan.ALLOC_GCSPY; } } if (isPrefix("Lorg/jikesrvm/mm/mmtk/ReferenceProcessor", clsBA)) return Plan.ALLOC_DEFAULT; if (isPrefix("Lorg/mmtk/", clsBA) || isPrefix("Lorg/jikesrvm/mm/", clsBA) || isPrefix("Lorg/jikesrvm/memorymanagers/mminterface/VM_GCMapIteratorGroup", clsBA)) { return Plan.ALLOC_IMMORTAL; } } return type.getMMAllocator(); } /** * Determine the default allocator to be used for a given type. * * @param type The type in question * @return The allocator to use for allocating instances of type * <code>type</code>. */ @Interruptible private static int pickAllocatorForType(VM_Type type) { int allocator = Plan.ALLOC_DEFAULT; if (type.isArrayType() && type.asArray().getElementType().isPrimitiveType()) { allocator = Plan.ALLOC_NON_REFERENCE; } byte[] typeBA = type.getDescriptor().toByteArray(); if (Selected.Constraints.get().withGCspy()) { if (isPrefix("Lorg/mmtk/vm/gcspy/", typeBA) || isPrefix("[Lorg/mmtk/vm/gcspy/", typeBA)) { allocator = Plan.ALLOC_GCSPY; } } if (isPrefix("Lorg/mmtk/", typeBA) || isPrefix("Lorg/jikesrvm/mm/", typeBA) || isPrefix("Lorg/jikesrvm/memorymanagers/", typeBA) || isPrefix("Lorg/jikesrvm/scheduler/VM_Processor;", typeBA) || isPrefix("Lorg/jikesrvm/scheduler/greenthreads/VM_GreenProcessor;", typeBA) || isPrefix("Lorg/jikesrvm/jni/VM_JNIEnvironment;", typeBA)) { allocator = Plan.ALLOC_IMMORTAL; } if (Selected.Constraints.get().needsImmortalTypeInfo() && (isPrefix("Lorg/jikesrvm/classloader/VM_Class", typeBA) || isPrefix("Lorg/jikesrvm/classloader/VM_Array", typeBA))) { allocator = Plan.ALLOC_IMMORTAL; } return allocator; } /*********************************************************************** * These methods allocate memory. Specialized versions are available for * particular object types. *********************************************************************** */ /** * Allocate a scalar object. * * @param size Size in bytes of the object, including any headers * that need space. * @param tib Type of the object (pointer to TIB). * @param allocator Specify which allocation scheme/area JMTk should * allocate the memory from. * @param align the alignment requested; must be a power of 2. * @param offset the offset at which the alignment is desired. * @param site allocation site. * @return the initialized Object */ @Inline public static Object allocateScalar(int size, Object[] tib, int allocator, int align, int offset, int site) { Selected.Mutator mutator = Selected.Mutator.get(); allocator = mutator.checkAllocator(VM_Memory.alignUp(size, MIN_ALIGNMENT), align, allocator); Address region = allocateSpace(mutator, size, align, offset, allocator, site); Object result = VM_ObjectModel.initializeScalar(region, tib, size); mutator.postAlloc(ObjectReference.fromObject(result), ObjectReference.fromObject(tib), size, allocator); return result; } /** * Allocate an array object. This is the interruptible component, including throwing * an OutOfMemoryError for arrays that are too large. * * @param numElements number of array elements * @param logElementSize size in bytes of an array element, log base 2. * @param headerSize size in bytes of array header * @param tib type information block for array object * @param allocator int that encodes which allocator should be used * @param align the alignment requested; must be a power of 2. * @param offset the offset at which the alignment is desired. * @param site allocation site. * @return array object with header installed and all elements set * to zero/null * See also: bytecode 0xbc ("newarray") and 0xbd ("anewarray") */ @Inline @Interruptible public static Object allocateArray(int numElements, int logElementSize, int headerSize, Object[] tib, int allocator, int align, int offset, int site) { int elemBytes = numElements << logElementSize; if ((elemBytes >>> logElementSize) != numElements) { /* asked to allocate more than Integer.MAX_VALUE bytes */ throwLargeArrayOutOfMemoryError(); } int size = elemBytes + headerSize; return allocateArrayInternal(numElements, size, tib, allocator, align, offset, site); } /** * Throw an out of memory error due to an array allocation request that is * larger than the maximum allowed value. This is in a separate method * so it can be forced out of line. */ @NoInline @Interruptible private static void throwLargeArrayOutOfMemoryError() { throw new OutOfMemoryError(); } /** * Allocate an array object. * * @param numElements The number of element bytes * @param size size in bytes of array header * @param tib type information block for array object * @param allocator int that encodes which allocator should be used * @param align the alignment requested; must be a power of 2. * @param offset the offset at which the alignment is desired. * @param site allocation site. * @return array object with header installed and all elements set * to zero/null * See also: bytecode 0xbc ("newarray") and 0xbd ("anewarray") */ @Inline private static Object allocateArrayInternal(int numElements, int size, Object[] tib, int allocator, int align, int offset, int site) { Selected.Mutator mutator = Selected.Mutator.get(); allocator = mutator.checkAllocator(VM_Memory.alignUp(size, MIN_ALIGNMENT), align, allocator); Address region = allocateSpace(mutator, size, align, offset, allocator, site); Object result = VM_ObjectModel.initializeArray(region, tib, numElements, size); mutator.postAlloc(ObjectReference.fromObject(result), ObjectReference.fromObject(tib), size, allocator); return result; } /** * Allocate space for runtime allocation of an object * * @param mutator The mutator instance to be used for this allocation * @param bytes The size of the allocation in bytes * @param align The alignment requested; must be a power of 2. * @param offset The offset at which the alignment is desired. * @param allocator The MMTk allocator to be used (if allocating) * @param site Allocation site. * @return The first byte of a suitably sized and aligned region of memory. */ @Inline private static Address allocateSpace(Selected.Mutator mutator, int bytes, int align, int offset, int allocator, int site) { /* MMTk requests must be in multiples of MIN_ALIGNMENT */ bytes = VM_Memory.alignUp(bytes, MIN_ALIGNMENT); /* Now make the request */ Address region; region = mutator.alloc(bytes, align, offset, allocator, site); /* TODO: if (Stats.GATHER_MARK_CONS_STATS) Plan.cons.inc(bytes); */ if (CHECK_MEMORY_IS_ZEROED) Memory.assertIsZeroed(region, bytes); return region; } /** * Allocate space for GC-time copying of an object * * @param collector The collector instance to be used for this allocation * @param bytes The size of the allocation in bytes * @param align The alignment requested; must be a power of 2. * @param offset The offset at which the alignment is desired. * @param from The source object from which this is to be copied * @return The first byte of a suitably sized and aligned region of memory. */ @Inline public static Address allocateSpace(Selected.Collector collector, int bytes, int align, int offset, int allocator, ObjectReference from) { /* MMTk requests must be in multiples of MIN_ALIGNMENT */ bytes = VM_Memory.alignUp(bytes, MIN_ALIGNMENT); /* Now make the request */ Address region; region = collector.allocCopy(from, bytes, align, offset, allocator); /* TODO: if (Stats.GATHER_MARK_CONS_STATS) Plan.mark.inc(bytes); */ if (CHECK_MEMORY_IS_ZEROED) Memory.assertIsZeroed(region, bytes); return region; } /** * Align an allocation using some modulo arithmetic to guarantee the * following property:<br> * <code>(region + offset) % alignment == 0</code> * * @param initialOffset The initial (unaligned) start value of the * allocated region of memory. * @param align The alignment requested, must be a power of two * @param offset The offset at which the alignment is desired * @return <code>initialOffset</code> plus some delta (possibly 0) such * that the return value is aligned according to the above * constraints. */ @Inline public static Offset alignAllocation(Offset initialOffset, int align, int offset) { Address region = VM_Memory.alignUp(initialOffset.toWord().toAddress(), MIN_ALIGNMENT); return Allocator.alignAllocationNoFill(region, align, offset).toWord().toOffset(); } /** * Private allocation of code array * * @param numInstrs number of instructions * @param isHot is this a request for hot code space allocation? * @return The array */ @Interruptible private static Object _allocateCode(VM_Array type, int numInstrs, boolean isHot) { int headerSize = VM_ObjectModel.computeArrayHeaderSize(type); int align = VM_ObjectModel.getAlignment(type); int offset = VM_ObjectModel.getOffsetForAlignment(type); int width = type.getLogElementSize(); Object[] tib = type.getTypeInformationBlock(); int allocator = isHot ? Plan.ALLOC_HOT_CODE : Plan.ALLOC_COLD_CODE; return allocateArray(numInstrs, width, headerSize, tib, allocator, align, offset, Plan.DEFAULT_SITE); } /** * Allocate a VM_CodeArray into a code space. * Currently the interface is fairly primitive; * just the number of instructions in the code array and a boolean * to indicate hot or cold code. * @param numInstrs number of instructions * @param isHot is this a request for hot code space allocation? * @return The array */ @Interruptible public static VM_CodeArray allocateCode(int numInstrs, boolean isHot) { VM_Array type = VM_Type.CodeArrayType; return (VM_CodeArray) _allocateCode(type, numInstrs, isHot); } /** * Allocate a SubordianteArchitecture VM_CodeArray into a code space. * Currently the interface is fairly primitive; * just the number of instructions in the code array and a boolean * to indicate hot or cold code. * @param numInstrs number of instructions * @param isHot is this a request for hot code space allocation? * @return The array */ @Interruptible public static org.jikesrvm.SubordinateArchitecture.VM_CodeArray allocateCodeSubArch(int numInstrs, boolean isHot) { VM_Array type = VM_Type.SubArchCodeArrayType; return (org.jikesrvm.SubordinateArchitecture.VM_CodeArray) _allocateCode(type, numInstrs, isHot); } /** * Allocate a stack * @param bytes The number of bytes to allocate * @param immortal Is the stack immortal and non-moving? * @return The stack */ @Inline @Interruptible public static byte[] newStack(int bytes, boolean immortal) { if (!VM.runningVM) { return new byte[bytes]; } else { VM_Array stackType = VM_Array.ByteArray; int headerSize = VM_ObjectModel.computeArrayHeaderSize(stackType); int align = VM_ObjectModel.getAlignment(stackType); int offset = VM_ObjectModel.getOffsetForAlignment(stackType); int width = stackType.getLogElementSize(); Object[] stackTib = stackType.getTypeInformationBlock(); return (byte[]) allocateArray(bytes, width, headerSize, stackTib, (immortal ? Plan.ALLOC_IMMORTAL_STACK : Plan.ALLOC_STACK), align, offset, Plan.DEFAULT_SITE); } } /** * Allocate a reference offset array * * @param size The size of the array */ @Inline @Interruptible public static int[] newReferenceOffsetArray(int size) { if (!VM.runningVM) { return new int[size]; } VM_Array arrayType = VM_Array.IntArray; int headerSize = VM_ObjectModel.computeArrayHeaderSize(arrayType); int align = VM_ObjectModel.getAlignment(arrayType); int offset = VM_ObjectModel.getOffsetForAlignment(arrayType); int width = arrayType.getLogElementSize(); Object[] arrayTib = arrayType.getTypeInformationBlock(); return (int[]) allocateArray(size, width, headerSize, arrayTib, (Selected.Constraints.get().needsImmortalTypeInfo() ? Plan.ALLOC_IMMORTAL : Plan.ALLOC_DEFAULT), align, offset, Plan.DEFAULT_SITE); } /** * Allocate a new type information block (TIB). * * @param n the number of slots in the TIB to be allocated * @return the new TIB */ @Inline @Interruptible public static Object[] newTIB(int n) { if (!VM.runningVM) { return new Object[n]; } VM_Array objectArrayType = VM_Type.JavaLangObjectArrayType; Object[] objectArrayTib = objectArrayType.getTypeInformationBlock(); int align = VM_ObjectModel.getAlignment(objectArrayType); int offset = VM_ObjectModel.getOffsetForAlignment(objectArrayType); Object result = allocateArray(n, objectArrayType.getLogElementSize(), VM_ObjectModel.computeArrayHeaderSize(objectArrayType), objectArrayTib, Plan.ALLOC_IMMORTAL, align, offset, Plan.DEFAULT_SITE); return (Object[]) result; } /** * Allocate a contiguous VM_CompiledMethod array * @param n The number of objects * @return The contiguous object array */ @Inline @Interruptible public static VM_CompiledMethod[] newContiguousCompiledMethodArray(int n) { return new VM_CompiledMethod[n]; } /* * Will this object move (allows us to optimize some JNI calls) * */ public static boolean willNeverMove(Object obj) { return Selected.Plan.get().willNeverMove(ObjectReference.fromObject(obj)); } /*********************************************************************** * * Finalizers */ /** * Adds an object to the list of objects to have their * <code>finalize</code> method called when they are reclaimed. * * @param object the object to be added to the finalizer's list */ @Interruptible public static void addFinalizer(Object object) { Finalizer.addCandidate(ObjectReference.fromObject(object)); } /** * Gets an object from the list of objects that are to be reclaimed * and need to have their <code>finalize</code> method called. * * @return the object needing to be finialized */ public static Object getFinalizedObject() { return Finalizer.get().toObject(); } /*********************************************************************** * * References */ /** * Add a soft reference to the list of soft references. * * @param obj the soft reference to be added to the list */ @Interruptible public static void addSoftReference(SoftReference<?> obj, Object referent) { ReferenceProcessor.addSoftCandidate(obj,ObjectReference.fromObject(referent)); } /** * Add a weak reference to the list of weak references. * * @param obj the weak reference to be added to the list */ @Interruptible public static void addWeakReference(WeakReference<?> obj, Object referent) { ReferenceProcessor.addWeakCandidate(obj,ObjectReference.fromObject(referent)); } /** * Add a phantom reference to the list of phantom references. * * @param obj the phantom reference to be added to the list */ @Interruptible public static void addPhantomReference(PhantomReference<?> obj, Object referent) { ReferenceProcessor.addPhantomCandidate(obj,ObjectReference.fromObject(referent)); } /*********************************************************************** * * Tracing */ /*********************************************************************** * * Heap size and heap growth */ /** * Return the max heap size in bytes (as set by -Xmx). * * @return The max heap size in bytes (as set by -Xmx). */ public static Extent getMaxHeapSize() { return HeapGrowthManager.getMaxHeapSize(); } /*********************************************************************** * * Miscellaneous */ /** * A new type has been resolved by the VM. Create a new MM type to * reflect the VM type, and associate the MM type with the VM type. * * @param vmType The newly resolved type */ @Interruptible public static void notifyClassResolved(VM_Type vmType) { vmType.setMMAllocator(pickAllocatorForType(vmType)); } /** * Check if object might be a TIB. * * @param obj address of object to check * @return <code>false</code> if the object is in the wrong * allocation scheme/area for a TIB, <code>true</code> otherwise */ @Inline public static boolean mightBeTIB(ObjectReference obj) { return !obj.isNull() && Space.isMappedObject(obj) && Space.isImmortal(obj) && Space.isMappedObject(ObjectReference.fromObject(VM_ObjectModel.getTIB(obj))); } /** * Returns true if GC is in progress. * * @return True if GC is in progress. */ public static boolean gcInProgress() { return Plan.gcInProgress(); } /** * Start the GCspy server */ @Interruptible public static void startGCspyServer() { GCspy.startGCspyServer(); } /** * Flush the mutator context. */ public static void flushMutatorContext() { Selected.Mutator.get().flush(); } /** * Return the number of specialized methods. */ public static int numSpecializedMethods() { return VM_SpecializedScanMethod.ENABLED ? Selected.Constraints.get().numSpecializedScans() : 0; } /** * Initialize a specified specialized method. * * @param id the specializedMethod */ @Interruptible public static VM_SpecializedMethod createSpecializedMethod(int id) { if (VM.VerifyAssertions) { VM._assert(VM_SpecializedScanMethod.ENABLED); VM._assert(id < Selected.Constraints.get().numSpecializedScans()); } /* What does the plan want us to specialize this to? */ Class<?> traceClass = Selected.Plan.get().getSpecializedScanClass(id); /* Create the specialized method */ return new VM_SpecializedScanMethod(id, VM_TypeReference.findOrCreate(traceClass)); } /*********************************************************************** * * Header initialization */ /** * Override the boot-time initialization method here, so that * the core JMTk code doesn't need to know about the * BootImageInterface type. */ @Interruptible public static void initializeHeader(BootImageInterface bootImage, Address ref, Object[] tib, int size, boolean isScalar) { // int status = VM_JavaHeader.readAvailableBitsWord(bootImage, ref); Word status = Selected.Plan.get().setBootTimeGCBits(ref, ObjectReference.fromObject(tib), size, Word.zero()); VM_JavaHeader.writeAvailableBitsWord(bootImage, ref, status); } /*********************************************************************** * * Deprecated and/or broken. The following need to be expunged. */ /** * Returns the maximum number of heaps that can be managed. * * @return the maximum number of heaps */ public static int getMaxHeaps() { /* * The boot record has a table of address ranges of the heaps, * the maximum number of heaps is used to size the table. */ return Space.MAX_SPACES; } /** * Allocate a contiguous int array * @param n The number of ints * @return The contiguous int array */ @Inline @Interruptible public static int[] newContiguousIntArray(int n) { return new int[n]; } }