blob: 8b347cd022946cc13fc8748e6d5d2f98271a3ed7 [file] [log] [blame]
/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* 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/eclipse-1.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_BLOCK_SIZE) ; }
}