| /* |
| * 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); |
| } |