blob: 6e7125792b9e46a393e98a6dcf9e54c13f8ebaaa [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.immix;
import static org.mmtk.policy.immix.ImmixConstants.*;
import org.mmtk.utility.Constants;
import org.mmtk.vm.VM;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Extent;
import org.vmmagic.unboxed.Offset;
/**
* This class defines operations over block-granularity meta-data
*
*/
@Uninterruptible
public class Block implements Constants {
static Address align(final Address ptr) {
return ptr.toWord().and(BLOCK_MASK.not()).toAddress();
}
public static boolean isAligned(final Address address) {
return address.EQ(align(address));
}
private static int getChunkIndex(final Address block) {
return block.toWord().and(CHUNK_MASK).rshl(LOG_BYTES_IN_BLOCK).toInt();
}
/***************************************************************************
* Block marking
*/
public static boolean isUnused(final Address address) {
return getBlockMarkState(address) == UNALLOCATED_BLOCK_STATE;
}
static boolean isUnusedState(Address cursor) {
return cursor.loadShort() == UNALLOCATED_BLOCK_STATE;
}
static short getMarkState(Address cursor) {
return cursor.loadShort();
}
static void setState(Address cursor, short value) {
cursor.store(value);
}
public static short getBlockMarkState(Address address) {
return getBlockMarkStateAddress(address).loadShort();
}
static void setBlockAsInUse(Address address) {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isUnused(address));
setBlockState(address, UNMARKED_BLOCK_STATE);
}
public static void setBlockAsReused(Address address) {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!isUnused(address));
setBlockState(address, REUSED_BLOCK_STATE);
}
static void setBlockAsUnallocated(Address address) {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!isUnused(address));
getBlockMarkStateAddress(address).store(UNALLOCATED_BLOCK_STATE);
}
private static void setBlockState(Address address, short value) {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(value != UNALLOCATED_BLOCK_STATE);
getBlockMarkStateAddress(address).store(value);
}
static Address getBlockMarkStateAddress(Address address) {
Address chunk = Chunk.align(address);
int index = getChunkIndex(address);
Address rtn = chunk.plus(Chunk.BLOCK_STATE_TABLE_OFFSET).plus(index<<LOG_BYTES_IN_BLOCK_STATE_ENTRY);
if (VM.VERIFY_ASSERTIONS) {
Address block = chunk.plus(index<<LOG_BYTES_IN_BLOCK);
VM.assertions._assert(isAligned(block));
boolean valid = rtn.GE(chunk.plus(Chunk.BLOCK_STATE_TABLE_OFFSET)) && rtn.LT(chunk.plus(Chunk.BLOCK_STATE_TABLE_OFFSET+BLOCK_STATE_TABLE_BYTES));
VM.assertions._assert(valid);
}
return rtn;
}
/***************************************************************************
* Sweeping
*/
static short sweepOneBlock(Address block, int[] markHistogram, final byte markState, final boolean resetMarkState) {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isAligned(block));
final boolean unused = isUnused(block);
if (unused && !SANITY_CHECK_LINE_MARKS)
return 0;
Address markTable = Line.getBlockMarkTable(block);
short markCount = 0;
short conservativeSpillCount = 0;
byte mark, lastMark = 0;
for (int offset = 0; offset < (LINES_IN_BLOCK<<Line.LOG_BYTES_IN_LINE_STATUS); offset += Line.BYTES_IN_LINE_STATUS) {
if (VM.VERIFY_ASSERTIONS) {
VM.assertions._assert(markTable.plus(offset).GE(Chunk.align(block).plus(Chunk.LINE_MARK_TABLE_OFFSET)));
VM.assertions._assert(markTable.plus(offset).LT(Chunk.align(block).plus(Chunk.LINE_MARK_TABLE_OFFSET+Line.LINE_MARK_TABLE_BYTES)));
}
mark = markTable.loadByte(Offset.fromIntZeroExtend(offset));
if (resetMarkState)
markTable.store((byte) (mark == markState ? RESET_LINE_MARK_STATE : 0), Offset.fromIntZeroExtend(offset));
if (mark == markState)
markCount++;
else if (lastMark == markState)
conservativeSpillCount++;
else if (SANITY_CHECK_LINE_MARKS && lastMark != markState) {
VM.memory.zero(block.plus(offset<<(LOG_BYTES_IN_LINE-Line.LOG_BYTES_IN_LINE_STATUS)),Extent.fromIntZeroExtend(BYTES_IN_LINE));
}
lastMark = mark;
}
if (VM.VERIFY_ASSERTIONS) {
VM.assertions._assert(markCount <= LINES_IN_BLOCK);
VM.assertions._assert(markCount + conservativeSpillCount <= LINES_IN_BLOCK);
VM.assertions._assert(markCount == 0 || !isUnused(block));
}
getDefragStateAddress(block).store(conservativeSpillCount);
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(markCount >= conservativeSpillCount);
markHistogram[conservativeSpillCount] += markCount;
markCount = (short) (markCount + conservativeSpillCount);
return markCount;
}
/****************************************************************************
* Block defrag state
*/
public static boolean isDefragSource(Address address) {
return getDefragStateAddress(address).loadShort() == BLOCK_IS_DEFRAG_SOURCE;
}
static void clearConservativeSpillCount(Address address) {
getDefragStateAddress(address).store((short) 0);
}
static short getConservativeSpillCount(Address address) {
return getDefragStateAddress(address).loadShort();
}
static Address getDefragStateAddress(Address address) {
Address chunk = Chunk.align(address);
int index = getChunkIndex(address);
Address rtn = chunk.plus(Chunk.BLOCK_DEFRAG_STATE_TABLE_OFFSET).plus(index<<LOG_BYTES_IN_BLOCK_DEFRAG_STATE_ENTRY);
if (VM.VERIFY_ASSERTIONS) {
Address block = chunk.plus(index<<LOG_BYTES_IN_BLOCK);
VM.assertions._assert(isAligned(block));
boolean valid = rtn.GE(chunk.plus(Chunk.BLOCK_DEFRAG_STATE_TABLE_OFFSET)) && rtn.LT(chunk.plus(Chunk.BLOCK_DEFRAG_STATE_TABLE_OFFSET+BLOCK_DEFRAG_STATE_TABLE_BYTES));
VM.assertions._assert(valid);
}
return rtn;
}
static void resetLineMarksAndDefragStateTable(short threshold, Address markStateBase, Address defragStateBase,
Address lineMarkBase, int block) {
Offset csOffset = Offset.fromIntZeroExtend(block<<LOG_BYTES_IN_BLOCK_DEFRAG_STATE_ENTRY);
short state = defragStateBase.loadShort(csOffset);
short defragState = BLOCK_IS_NOT_DEFRAG_SOURCE;
if (state >= threshold) defragState = BLOCK_IS_DEFRAG_SOURCE;
defragStateBase.store(defragState, csOffset);
}
private static final short UNALLOCATED_BLOCK_STATE = 0;
private static final short UNMARKED_BLOCK_STATE = (short) (MAX_BLOCK_MARK_STATE + 1);
private static final short REUSED_BLOCK_STATE = (short) (MAX_BLOCK_MARK_STATE + 2);
private static final short BLOCK_IS_NOT_DEFRAG_SOURCE = 0;
private static final short BLOCK_IS_DEFRAG_SOURCE = 1;
/* block states */
static final int LOG_BYTES_IN_BLOCK_STATE_ENTRY = LOG_BYTES_IN_SHORT; // use a short for now
static final int BYTES_IN_BLOCK_STATE_ENTRY = 1<<LOG_BYTES_IN_BLOCK_STATE_ENTRY;
static final int BLOCK_STATE_TABLE_BYTES = BLOCKS_IN_CHUNK<<LOG_BYTES_IN_BLOCK_STATE_ENTRY;
/* per-block defrag state */
static final int LOG_BYTES_IN_BLOCK_DEFRAG_STATE_ENTRY = LOG_BYTES_IN_SHORT;
static final int BYTES_IN_BLOCK_DEFRAG_STATE_ENTRY = 1<<LOG_BYTES_IN_BLOCK_DEFRAG_STATE_ENTRY;
static final int BLOCK_DEFRAG_STATE_TABLE_BYTES = BLOCKS_IN_CHUNK<<LOG_BYTES_IN_BLOCK_DEFRAG_STATE_ENTRY;
}