/*
* Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.max.vm.heap;
import com.sun.max.annotate.*;
import com.sun.max.memory.*;
import com.sun.max.program.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.*;
import com.sun.max.vm.code.*;
import com.sun.max.vm.heap.debug.*;
import com.sun.max.vm.object.*;
import com.sun.max.vm.runtime.*;
/**
*/
public class LinearAllocatorRegion extends LinearAllocationMemoryRegion {
public void setMark(Address mark) {
this.mark.set(mark.wordAligned());
}
public LinearAllocatorRegion(String description) {
setRegionName(description);
}
public LinearAllocatorRegion(Address start, Size size, String description) {
super(start, size);
mark.set(start.wordAligned());
setRegionName(description);
}
public Size allocationSize(Size cellSize) {
return DebugHeap.adjustForDebugTag(cellSize.asPointer()).asSize();
}
/**
* Allocates some memory from this region.
*
* Garbage Collector considerations:
*
* If the garbage collector expects to be able to scan this memory region as a sequence of
* well-formed, contiguous objects between {@link #start()} and {@link #mark()}, then
* the caller(s) of this method must ensure that safepoints are {@linkplain SafepointPoll#disable() disabled}
* until the space allocated by this call has been initialized with the appropriate object header(s).
*
* Thread safety considerations: The caller(s) are responsible for ensuring that calls to this
* method are synchronized. Failure to do so will leave the {@link #mark()} in an inconsistent state.
*
* @param size the requested cell size to be allocated. This value must be {@linkplain Address#isWordAligned() word aligned}.
* @param adjustForDebugTag specifies if an extra word is to be reserved before the cell for the debug tag word
*/
public Pointer allocate(Size size, boolean adjustForDebugTag) {
if (!size.isWordAligned()) {
FatalError.unexpected("Allocation size must be word aligned");
}
Pointer oldAllocationMark = mark();
Pointer cell = adjustForDebugTag ? DebugHeap.adjustForDebugTag(oldAllocationMark) : oldAllocationMark;
Address end = cell.plus(size);
if (end.greaterThan(end())) {
if (MaxineVM.isHosted()) {
throw ProgramError.unexpected("out of space in linear allocator region");
}
return Pointer.zero();
}
setMark(end);
return cell;
}
/**
* Set size according to the current allocations. This also effectively disables further allocations.
*/
@HOSTED_ONLY
public void trim() {
setSize(getAllocationMark().minus(start()).asSize());
}
@INLINE
private void scanReferences(PointerIndexVisitor pointerIndexVisitor, Pointer refMap, int refmapWordIndex, boolean logging) {
final int firstWordIndex = refmapWordIndex << Word.widthValue().log2numberOfBits;
final Pointer base = start.plusWords(firstWordIndex).asPointer();
long refmapWord = refMap.getLong(refmapWordIndex);
long w = refmapWord;
int bitIndexInWord = 0;
while (w != 0L) {
bitIndexInWord += Address.fromLong(w).leastSignificantBitSet();
if (logging) {
final Address value = base.getWord(bitIndexInWord).asAddress();
if (!value.isZero() && !contains(value) && !Code.bootCodeRegion().contains(value)) {
final Pointer address = base.plusWords(bitIndexInWord);
Heap.rootScanLogger.logVisitReferenceMapSlot(firstWordIndex + bitIndexInWord, address, value);
}
}
pointerIndexVisitor.visit(base, bitIndexInWord);
if (++bitIndexInWord == 64) {
return;
}
w = refmapWord >>> bitIndexInWord;
}
}
@INLINE
private void scanReferences(PointerIndexVisitor pointerIndexVisitor, Pointer refMap, int refmapWordIndex, int firstBit, int lastBit, boolean logging) {
final int firstWordIndex = refmapWordIndex << Word.widthValue().log2numberOfBits;
final Pointer base = start.plusWords(firstWordIndex).asPointer();
Address refmapWord = refMap.getWord(refmapWordIndex).asAddress();
Address w = refmapWord.unsignedShiftedRight(firstBit);
int bitIndex = firstBit;
while (!w.isZero()) {
bitIndex += w.leastSignificantBitSet();
if (bitIndex >= lastBit) {
return;
}
if (logging) {
final Pointer address = base.plusWords(bitIndex);
final Address value = address.getWord().asAddress();
if (!value.isZero() && !contains(value) && !Code.bootCodeRegion().contains(value)) {
Heap.rootScanLogger.logVisitReferenceMapSlot(firstWordIndex + bitIndex, address, value);
}
}
pointerIndexVisitor.visit(base, bitIndex);
w = refmapWord.unsignedShiftedRight(++bitIndex);
}
}
@INLINE
private void scanReferences(PointerIndexVisitor pointerIndexVisitor, Pointer refMap, int firstBitIndex, int lastBitIndex, boolean logging) {
final int mask = Word.widthValue().log2numberOfBits - 1;
final int firstRefMapWordIndex = firstBitIndex >> Word.widthValue().log2numberOfBits;
final int lastRefMapWordIndex = lastBitIndex >> Word.widthValue().log2numberOfBits;
int refMapWordIndex = firstRefMapWordIndex;
int nextBitIndex = firstBitIndex;
if (refMapWordIndex < lastRefMapWordIndex) {
if ((firstBitIndex & mask) != 0) {
// first bit is not at a word boundary. Scan reference from the first bit index to the last bit of the current refmap word
final int lastBit = (refMapWordIndex + 1) << Word.widthValue().log2numberOfBits;
scanReferences(pointerIndexVisitor, refMap, refMapWordIndex++, firstBitIndex, lastBit, logging);
}
while (refMapWordIndex < lastRefMapWordIndex) {
scanReferences(pointerIndexVisitor, refMap, refMapWordIndex++, logging);
}
nextBitIndex = lastBitIndex & ~mask;
}
if ((lastBitIndex & mask) != 0) {
scanReferences(pointerIndexVisitor, refMap, refMapWordIndex, nextBitIndex, lastBitIndex, logging);
} else {
scanReferences(pointerIndexVisitor, refMap, refMapWordIndex, logging);
}
}
@INLINE
protected final void scanReferences(PointerIndexVisitor pointerIndexVisitor, byte [] referenceMapBytes, Address rangeStart, Address rangeEnd, boolean logging) {
final int firstBitIndex = rangeStart.minus(start).unsignedShiftedRight(Word.widthValue().log2numberOfBytes).toInt();
final int lastBitIndex = rangeEnd.minus(start).unsignedShiftedRight(Word.widthValue().log2numberOfBytes).toInt();
final Pointer refMap = ArrayAccess.elementPointer(referenceMapBytes, 0);
scanReferences(pointerIndexVisitor, refMap, firstBitIndex, lastBitIndex, logging);
}
@INLINE
protected final void scanReferenceMap(PointerIndexVisitor pointerIndexVisitor, byte [] referenceMapBytes, int refMapWords, boolean logging) {
final Pointer refMap = ArrayAccess.elementPointer(referenceMapBytes, 0);
int refMapWordIndex = 0;
while (refMapWordIndex < refMapWords) {
scanReferences(pointerIndexVisitor, refMap, refMapWordIndex++, logging);
}
}
}