001 /*
002 * This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 * This file is licensed to You under the Eclipse Public License (EPL);
005 * You may not use this file except in compliance with the License. You
006 * may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 * See the COPYRIGHT.txt file distributed with this work for information
011 * regarding copyright ownership.
012 */
013 package org.mmtk.policy.immix;
014
015 import static org.mmtk.policy.immix.ImmixConstants.*;
016
017 import org.mmtk.utility.Constants;
018 import org.mmtk.vm.VM;
019
020 import org.vmmagic.pragma.Inline;
021 import org.vmmagic.pragma.Uninterruptible;
022 import org.vmmagic.unboxed.Address;
023 import org.vmmagic.unboxed.ObjectReference;
024 import org.vmmagic.unboxed.Offset;
025
026 @Uninterruptible
027 public class Line implements Constants {
028
029 public static Address align(Address ptr) {
030 return ptr.toWord().and(LINE_MASK.not()).toAddress();
031 }
032
033 public static boolean isAligned(Address address) {
034 return address.EQ(align(address));
035 }
036
037 static int getChunkIndex(Address line) {
038 return line.toWord().and(CHUNK_MASK).rshl(LOG_BYTES_IN_LINE).toInt();
039 }
040
041 /***************************************************************************
042 * Line marking
043 */
044 static void mark(Address address, final byte markValue) {
045 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Block.isUnused(Block.align(address)));
046 getMarkAddress(address).store(markValue);
047 }
048
049 static void markMultiLine(Address start, ObjectReference object, final byte markValue) {
050 /* endLine is the address of the last (highest) line touched by this object */
051 Address endLine = Line.align(VM.objectModel.getObjectEndAddress(object).minus(1));
052 Address line = Line.align(start.plus(BYTES_IN_LINE));
053 while (line.LT(endLine)) {
054 if (VM.VERIFY_ASSERTIONS)
055 VM.assertions._assert(Block.align(start).EQ(Block.align(line)));
056 mark(line, markValue);
057 line = line.plus(BYTES_IN_LINE);
058 }
059 }
060
061 /***************************************************************************
062 * Scanning through avail lines
063 */
064 public static Address getChunkMarkTable(Address chunk) {
065 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Chunk.isAligned(chunk));
066 return getMarkAddress(chunk);
067 }
068
069 public static Address getBlockMarkTable(Address block) {
070 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Block.isAligned(block));
071 return getMarkAddress(block);
072 }
073
074 @Inline
075 public static int getNextUnavailable(Address baseLineAvailAddress, int line, final byte unavailableState) {
076 while (line < LINES_IN_BLOCK &&
077 baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS)) < unavailableState)
078 line++;
079 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line <= LINES_IN_BLOCK);
080 return line;
081 }
082
083 @Inline
084 public static int getNextAvailable(Address baseLineAvailAddress, int line, final byte unavailableState) {
085 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line < LINES_IN_BLOCK);
086 byte last = baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS));
087 byte thisline;
088 line++;
089 while (line < LINES_IN_BLOCK) {
090 thisline = baseLineAvailAddress.loadByte(Offset.fromIntZeroExtend(line<<Line.LOG_BYTES_IN_LINE_STATUS));
091 if (thisline < unavailableState && last < unavailableState)
092 break;
093 last = thisline;
094 line++;
095 }
096 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(line >= 0 && line <= LINES_IN_BLOCK);
097 return line;
098 }
099
100 private static Address getMetaAddress(Address address, final int tableOffset) {
101 Address chunk = Chunk.align(address);
102 int index = getChunkIndex(address);
103 Address rtn = chunk.plus(tableOffset + (index<<LOG_BYTES_IN_LINE_STATUS));
104 if (VM.VERIFY_ASSERTIONS) {
105 Address line = chunk.plus(index<<LOG_BYTES_IN_LINE);
106 VM.assertions._assert(isAligned(line));
107 VM.assertions._assert(align(address).EQ(line));
108 boolean valid = rtn.GE(chunk.plus(tableOffset)) && rtn.LT(chunk.plus(tableOffset + LINE_MARK_TABLE_BYTES));
109 VM.assertions._assert(valid);
110 }
111 return rtn;
112 }
113
114 private static Address getMarkAddress(Address address) {
115 return getMetaAddress(address, Chunk.LINE_MARK_TABLE_OFFSET);
116 }
117
118 /* per-line mark bytes */
119 static final int LOG_BYTES_IN_LINE_STATUS = 0;
120 static final int BYTES_IN_LINE_STATUS = 1<<LOG_BYTES_IN_LINE_STATUS;
121
122 static final int LINE_MARK_TABLE_BYTES = LINES_IN_CHUNK<<LOG_BYTES_IN_LINE_STATUS;
123 static final int LOG_LINE_MARK_BYTES_PER_BLOCK = LOG_LINES_IN_BLOCK+LOG_BYTES_IN_LINE_STATUS;
124 static final int LINE_MARK_BYTES_PER_BLOCK = (1<<LOG_LINE_MARK_BYTES_PER_BLOCK);
125 }