/* * 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.mmtk.policy; import org.mmtk.plan.markcompact.MC; import org.mmtk.utility.Conversions; import org.mmtk.utility.alloc.Allocator; import org.mmtk.utility.alloc.BumpPointer; import org.mmtk.vm.VM; import org.vmmagic.pragma.*; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Extent; import org.vmmagic.unboxed.ObjectReference; /** * This class implements unsynchronized (local) elements of a * sliding mark-compact collector. Allocation is via the bump pointer * (@see BumpPointer). * * @see BumpPointer * @see MarkCompactSpace */ @Uninterruptible public final class MarkCompactLocal extends BumpPointer { /** * Constructor * * @param space The space to bump point into. */ public MarkCompactLocal(MarkCompactSpace space) { super(space, true); } /** * Perform the compacting phase of the collection. */ public void compact() { /* Has this allocator ever allocated anything? */ if (initialRegion.isZero()) return; /* Loop through active regions or until the last region */ Address start = initialRegion; Address allocStart = initialRegion; Address allocEnd = initialRegion.plus(REGION_LIMIT_OFFSET).loadAddress(); Address allocCursor = allocStart.plus(DATA_START_OFFSET); /* Keep track of which regions are being used */ int oldPages = 0; int newPages = Conversions.bytesToPages(allocEnd.diff(allocStart).plus(BYTES_IN_ADDRESS)); while (!start.isZero()) { /* Get the end of this region */ Address end = start.plus(REGION_LIMIT_OFFSET).loadAddress(); Address dataEnd = start.plus(DATA_END_OFFSET).loadAddress(); Address nextRegion = start.plus(NEXT_REGION_OFFSET).loadAddress(); oldPages += Conversions.bytesToPages(end.diff(start).plus(BYTES_IN_ADDRESS)); /* dataEnd = zero represents the current region. */ Address currentLimit = (dataEnd.isZero() ? cursor : dataEnd); ObjectReference current = VM.objectModel.getObjectFromStartAddress(start.plus(DATA_START_OFFSET)); while (VM.objectModel.refToAddress(current).LT(currentLimit) && !current.isNull()) { ObjectReference next = VM.objectModel.getNextObject(current); ObjectReference copyTo = MarkCompactSpace.getForwardingPointer(current); if (!copyTo.isNull() && Space.isInSpace(MC.MARK_COMPACT, copyTo)) { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!MarkCompactSpace.isMarked(current)); // To be copied. if (copyTo.toAddress().GT(allocEnd) || copyTo.toAddress().LT(allocStart)) { // changed regions. VM.memory.zero(allocCursor, allocEnd.diff(allocCursor).toWord().toExtent().plus(BYTES_IN_ADDRESS)); allocStart.store(allocCursor, DATA_END_OFFSET); allocStart = allocStart.plus(NEXT_REGION_OFFSET).loadAddress(); allocEnd = allocStart.plus(REGION_LIMIT_OFFSET).loadAddress(); allocCursor = allocStart.plus(DATA_START_OFFSET); newPages += Conversions.bytesToPages(allocEnd.diff(allocStart).plus(BYTES_IN_ADDRESS)); if (VM.VERIFY_ASSERTIONS) { VM.assertions._assert(allocCursor.LT(allocEnd) && allocCursor.GE(allocStart)); } } allocCursor = VM.objectModel.copyTo(current, copyTo, allocCursor); MarkCompactSpace.setForwardingPointer(copyTo, ObjectReference.nullReference()); } current = next; } if (dataEnd.isZero()) { break; } start = nextRegion; } Extent zeroBytes = allocEnd.diff(allocCursor).toWord().toExtent().plus(BYTES_IN_ADDRESS); VM.memory.zero(allocCursor, zeroBytes); allocStart.store(Address.zero(), DATA_END_OFFSET); region = allocStart; cursor = allocCursor; updateLimit(allocEnd, region, 0); if (oldPages > newPages) { ((MarkCompactSpace) space).unusePages((oldPages - newPages)); } // Zero during GC to help debugging. allocStart = allocStart.loadAddress(NEXT_REGION_OFFSET); while (!allocStart.isZero()) { allocStart.store(Address.zero(), DATA_END_OFFSET); if (VM.VERIFY_ASSERTIONS) { Address low = allocStart.plus(DATA_START_OFFSET); Extent size = allocStart.loadAddress(REGION_LIMIT_OFFSET).diff(allocStart).toWord().toExtent().minus(2 * BYTES_IN_ADDRESS); VM.memory.zero(low, size); } allocStart = allocStart.loadAddress(NEXT_REGION_OFFSET); } } /** * Perform a linear scan through the objects allocated by this bump pointer, * calculating where each live object will be post collection. */ public void calculateForwardingPointers() { /* Has this allocator ever allocated anything? */ if (initialRegion.isZero()) return; /* Loop through active regions or until the last region */ Address start = initialRegion; Address allocStart = initialRegion; Address allocDataEnd = initialRegion.plus(DATA_END_OFFSET).loadAddress(); Address allocLimit = (allocDataEnd.isZero() ? cursor : allocDataEnd); Address allocCursor = start.plus(DATA_START_OFFSET); while (!start.isZero()) { /* Get the end of this region */ Address dataEnd = start.plus(DATA_END_OFFSET).loadAddress(); /* dataEnd = zero represents the current region. */ Address currentLimit = (dataEnd.isZero() ? cursor : dataEnd); ObjectReference current = VM.objectModel.getObjectFromStartAddress(start.plus(DATA_START_OFFSET)); while (VM.objectModel.refToAddress(current).LT(currentLimit) && !current.isNull()) { ObjectReference next = VM.objectModel.getNextObject(current); if (MarkCompactSpace.toBeCompacted(current)) { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(MarkCompactSpace.getForwardingPointer(current).isNull()); // Fake - allocate it. int size = VM.objectModel.getSizeWhenCopied(current); int align = VM.objectModel.getAlignWhenCopied(current); int offset = VM.objectModel.getAlignOffsetWhenCopied(current); allocCursor = Allocator.alignAllocationNoFill(allocCursor, align, offset); boolean sameRegion = allocStart.EQ(start); if (!sameRegion && allocCursor.plus(size).GT(allocLimit)) { allocStart = allocStart.plus(NEXT_REGION_OFFSET).loadAddress(); allocDataEnd = allocStart.plus(DATA_END_OFFSET).loadAddress(); allocLimit = (allocDataEnd.isZero() ? cursor : allocDataEnd); allocCursor = Allocator.alignAllocationNoFill(allocStart.plus(DATA_START_OFFSET), align, offset); } ObjectReference target = VM.objectModel.getReferenceWhenCopiedTo(current, allocCursor); if (sameRegion && target.toAddress().GE(current.toAddress())) { MarkCompactSpace.setForwardingPointer(current, current); allocCursor = VM.objectModel.getObjectEndAddress(current); } else { MarkCompactSpace.setForwardingPointer(current, target); allocCursor = allocCursor.plus(size); } } current = next; } if (dataEnd.isZero()) { break; } start = start.plus(NEXT_REGION_OFFSET).loadAddress(); // Move on to next } } /** * Some pages are about to be re-used to satisfy a slow path request. * @param pages The number of pages. */ protected void reusePages(int pages) { ((MarkCompactSpace)space).reusePages(pages); } /** * Maximum size of a single region. Important for children that implement * load balancing or increments based on region size. * @return the maximum region size */ protected Extent maximumRegionSize() { return Extent.fromIntZeroExtend(4 << LOG_CHUNK_SIZE) ; } }