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