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.Uninterruptible; 021 import org.vmmagic.unboxed.Address; 022 import org.vmmagic.unboxed.Extent; 023 import org.vmmagic.unboxed.Offset; 024 025 /** 026 * This class defines operations over block-granularity meta-data 027 * 028 */ 029 @Uninterruptible 030 public class Block implements Constants { 031 032 static Address align(final Address ptr) { 033 return ptr.toWord().and(BLOCK_MASK.not()).toAddress(); 034 } 035 036 public static boolean isAligned(final Address address) { 037 return address.EQ(align(address)); 038 } 039 040 private static int getChunkIndex(final Address block) { 041 return block.toWord().and(CHUNK_MASK).rshl(LOG_BYTES_IN_BLOCK).toInt(); 042 } 043 044 /*************************************************************************** 045 * Block marking 046 */ 047 048 /** 049 * 050 */ 051 public static boolean isUnused(final Address address) { 052 return getBlockMarkState(address) == UNALLOCATED_BLOCK_STATE; 053 } 054 055 static boolean isUnusedState(Address cursor) { 056 return cursor.loadShort() == UNALLOCATED_BLOCK_STATE; 057 } 058 059 static short getMarkState(Address cursor) { 060 return cursor.loadShort(); 061 } 062 063 static void setState(Address cursor, short value) { 064 cursor.store(value); 065 } 066 067 public static short getBlockMarkState(Address address) { 068 return getBlockMarkStateAddress(address).loadShort(); 069 } 070 071 static void setBlockAsInUse(Address address) { 072 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isUnused(address)); 073 setBlockState(address, UNMARKED_BLOCK_STATE); 074 } 075 076 public static void setBlockAsReused(Address address) { 077 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!isUnused(address)); 078 setBlockState(address, REUSED_BLOCK_STATE); 079 } 080 081 static void setBlockAsUnallocated(Address address) { 082 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!isUnused(address)); 083 getBlockMarkStateAddress(address).store(UNALLOCATED_BLOCK_STATE); 084 } 085 086 private static void setBlockState(Address address, short value) { 087 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(value != UNALLOCATED_BLOCK_STATE); 088 getBlockMarkStateAddress(address).store(value); 089 } 090 091 static Address getBlockMarkStateAddress(Address address) { 092 Address chunk = Chunk.align(address); 093 int index = getChunkIndex(address); 094 Address rtn = chunk.plus(Chunk.BLOCK_STATE_TABLE_OFFSET).plus(index<<LOG_BYTES_IN_BLOCK_STATE_ENTRY); 095 if (VM.VERIFY_ASSERTIONS) { 096 Address block = chunk.plus(index<<LOG_BYTES_IN_BLOCK); 097 VM.assertions._assert(isAligned(block)); 098 boolean valid = rtn.GE(chunk.plus(Chunk.BLOCK_STATE_TABLE_OFFSET)) && rtn.LT(chunk.plus(Chunk.BLOCK_STATE_TABLE_OFFSET+BLOCK_STATE_TABLE_BYTES)); 099 VM.assertions._assert(valid); 100 } 101 return rtn; 102 } 103 104 /*************************************************************************** 105 * Sweeping 106 */ 107 108 /** 109 * 110 */ 111 static short sweepOneBlock(Address block, int[] markHistogram, final byte markState, final boolean resetMarkState) { 112 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isAligned(block)); 113 114 final boolean unused = isUnused(block); 115 if (unused && !SANITY_CHECK_LINE_MARKS) 116 return 0; 117 118 Address markTable = Line.getBlockMarkTable(block); 119 120 short markCount = 0; 121 short conservativeSpillCount = 0; 122 byte mark, lastMark = 0; 123 for (int offset = 0; offset < (LINES_IN_BLOCK<<Line.LOG_BYTES_IN_LINE_STATUS); offset += Line.BYTES_IN_LINE_STATUS) { 124 if (VM.VERIFY_ASSERTIONS) { 125 VM.assertions._assert(markTable.plus(offset).GE(Chunk.align(block).plus(Chunk.LINE_MARK_TABLE_OFFSET))); 126 VM.assertions._assert(markTable.plus(offset).LT(Chunk.align(block).plus(Chunk.LINE_MARK_TABLE_OFFSET+Line.LINE_MARK_TABLE_BYTES))); 127 } 128 mark = markTable.loadByte(Offset.fromIntZeroExtend(offset)); 129 if (resetMarkState) 130 markTable.store(mark == markState ? RESET_LINE_MARK_STATE : 0, Offset.fromIntZeroExtend(offset)); 131 132 if (mark == markState) 133 markCount++; 134 else if (lastMark == markState) 135 conservativeSpillCount++; 136 else if (SANITY_CHECK_LINE_MARKS && lastMark != markState) { 137 VM.memory.zero(false, block.plus(offset<<(LOG_BYTES_IN_LINE-Line.LOG_BYTES_IN_LINE_STATUS)),Extent.fromIntZeroExtend(BYTES_IN_LINE)); 138 } 139 140 lastMark = mark; 141 } 142 if (VM.VERIFY_ASSERTIONS) { 143 VM.assertions._assert(markCount <= LINES_IN_BLOCK); 144 VM.assertions._assert(markCount + conservativeSpillCount <= LINES_IN_BLOCK); 145 VM.assertions._assert(markCount == 0 || !isUnused(block)); 146 } 147 148 getDefragStateAddress(block).store(conservativeSpillCount); 149 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(markCount >= conservativeSpillCount); 150 markHistogram[conservativeSpillCount] += markCount; 151 152 markCount = (short) (markCount + conservativeSpillCount); 153 154 return markCount; 155 } 156 157 /**************************************************************************** 158 * Block defrag state 159 */ 160 161 /** 162 * 163 */ 164 public static boolean isDefragSource(Address address) { 165 return getDefragStateAddress(address).loadShort() == BLOCK_IS_DEFRAG_SOURCE; 166 } 167 168 static void clearConservativeSpillCount(Address address) { 169 getDefragStateAddress(address).store((short) 0); 170 } 171 172 static short getConservativeSpillCount(Address address) { 173 return getDefragStateAddress(address).loadShort(); 174 } 175 176 static Address getDefragStateAddress(Address address) { 177 Address chunk = Chunk.align(address); 178 int index = getChunkIndex(address); 179 Address rtn = chunk.plus(Chunk.BLOCK_DEFRAG_STATE_TABLE_OFFSET).plus(index<<LOG_BYTES_IN_BLOCK_DEFRAG_STATE_ENTRY); 180 if (VM.VERIFY_ASSERTIONS) { 181 Address block = chunk.plus(index<<LOG_BYTES_IN_BLOCK); 182 VM.assertions._assert(isAligned(block)); 183 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)); 184 VM.assertions._assert(valid); 185 } 186 return rtn; 187 } 188 189 static void resetLineMarksAndDefragStateTable(short threshold, Address markStateBase, Address defragStateBase, 190 Address lineMarkBase, int block) { 191 Offset csOffset = Offset.fromIntZeroExtend(block<<LOG_BYTES_IN_BLOCK_DEFRAG_STATE_ENTRY); 192 short state = defragStateBase.loadShort(csOffset); 193 short defragState = BLOCK_IS_NOT_DEFRAG_SOURCE; 194 if (state >= threshold) defragState = BLOCK_IS_DEFRAG_SOURCE; 195 defragStateBase.store(defragState, csOffset); 196 } 197 198 private static final short UNALLOCATED_BLOCK_STATE = 0; 199 private static final short UNMARKED_BLOCK_STATE = (short) (MAX_BLOCK_MARK_STATE + 1); 200 private static final short REUSED_BLOCK_STATE = (short) (MAX_BLOCK_MARK_STATE + 2); 201 202 private static final short BLOCK_IS_NOT_DEFRAG_SOURCE = 0; 203 private static final short BLOCK_IS_DEFRAG_SOURCE = 1; 204 205 /* block states */ 206 static final int LOG_BYTES_IN_BLOCK_STATE_ENTRY = LOG_BYTES_IN_SHORT; // use a short for now 207 static final int BYTES_IN_BLOCK_STATE_ENTRY = 1<<LOG_BYTES_IN_BLOCK_STATE_ENTRY; 208 static final int BLOCK_STATE_TABLE_BYTES = BLOCKS_IN_CHUNK<<LOG_BYTES_IN_BLOCK_STATE_ENTRY; 209 210 /* per-block defrag state */ 211 static final int LOG_BYTES_IN_BLOCK_DEFRAG_STATE_ENTRY = LOG_BYTES_IN_SHORT; 212 static final int BYTES_IN_BLOCK_DEFRAG_STATE_ENTRY = 1<<LOG_BYTES_IN_BLOCK_DEFRAG_STATE_ENTRY; 213 214 static final int BLOCK_DEFRAG_STATE_TABLE_BYTES = BLOCKS_IN_CHUNK<<LOG_BYTES_IN_BLOCK_DEFRAG_STATE_ENTRY; 215 }