/* * 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.Inline; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.ObjectReference; import org.vmmagic.unboxed.Offset; @Uninterruptible public class Line implements Constants { public static Address align(Address ptr) { return ptr.toWord().and(LINE_MASK.not()).toAddress(); } public static boolean isAligned(Address address) { return address.EQ(align(address)); } static int getChunkIndex(Address line) { return line.toWord().and(CHUNK_MASK).rshl(LOG_BYTES_IN_LINE).toInt(); } /*************************************************************************** * Line marking */ static void mark(Address address, final byte markValue) { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Block.isUnused(Block.align(address))); getMarkAddress(address).store(markValue); } static void markMultiLine(Address start, ObjectReference object, final byte markValue) { /* endLine is the address of the last (highest) line touched by this object */ Address endLine = Line.align(VM.objectModel.getObjectEndAddress(object).minus(1)); Address line = Line.align(start.plus(BYTES_IN_LINE)); while (line.LT(endLine)) { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Block.align(start).EQ(Block.align(line))); mark(line, markValue); line = line.plus(BYTES_IN_LINE); } } /*************************************************************************** * Scanning through avail lines */ public static Address getChunkMarkTable(Address chunk) { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Chunk.isAligned(chunk)); return getMarkAddress(chunk); } public static Address getBlockMarkTable(Address block) { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Block.isAligned(block)); return getMarkAddress(block); } @Inline public static int getNextUnavailable(Address baseLineAvailAddress, int line, final byte unavailableState) { while (line < LINES_IN_BLOCK && baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS)) < unavailableState) line++; if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line <= LINES_IN_BLOCK); return line; } @Inline public static int getNextAvailable(Address baseLineAvailAddress, int line, final byte unavailableState) { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line < LINES_IN_BLOCK); byte last = baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS)); byte thisline; line++; while (line < LINES_IN_BLOCK) { thisline = baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS)); if (thisline < unavailableState && last < unavailableState) break; last = thisline; line++; } if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line <= LINES_IN_BLOCK); return line; } private static Address getMetaAddress(Address address, final int tableOffset) { Address chunk = Chunk.align(address); int index = getChunkIndex(address); Address rtn = chunk.plus(tableOffset + (index<<LOG_BYTES_IN_LINE_STATUS)); if (VM.VERIFY_ASSERTIONS) { Address line = chunk.plus(index<<LOG_BYTES_IN_LINE); VM.assertions._assert(isAligned(line)); VM.assertions._assert(align(address).EQ(line)); boolean valid = rtn.GE(chunk.plus(tableOffset)) && rtn.LT(chunk.plus(tableOffset + LINE_MARK_TABLE_BYTES)); VM.assertions._assert(valid); } return rtn; } private static Address getMarkAddress(Address address) { return getMetaAddress(address, Chunk.LINE_MARK_TABLE_OFFSET); } /* per-line mark bytes */ static final int LOG_BYTES_IN_LINE_STATUS = 0; static final int BYTES_IN_LINE_STATUS = 1<<LOG_BYTES_IN_LINE_STATUS; static final int LINE_MARK_TABLE_BYTES = LINES_IN_CHUNK<<LOG_BYTES_IN_LINE_STATUS; static final int LOG_LINE_MARK_BYTES_PER_BLOCK = LOG_LINES_IN_BLOCK+LOG_BYTES_IN_LINE_STATUS; static final int LINE_MARK_BYTES_PER_BLOCK = (1<<LOG_LINE_MARK_BYTES_PER_BLOCK); }