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 */ 013package org.mmtk.policy.immix; 014 015import static org.mmtk.utility.Constants.BYTES_IN_PAGE; 016import static org.mmtk.utility.Constants.LOG_BYTES_IN_ADDRESS; 017 018import org.mmtk.plan.Plan; 019import org.mmtk.policy.Space; 020import org.mmtk.vm.VM; 021import org.vmmagic.pragma.Uninterruptible; 022import org.vmmagic.unboxed.Address; 023import org.vmmagic.unboxed.AddressArray; 024 025@Uninterruptible 026public final class ChunkList { 027 private static final int LOG_PAGES_IN_CHUNK_MAP_BLOCK = 0; 028 private static final int ENTRIES_IN_CHUNK_MAP_BLOCK = (BYTES_IN_PAGE << LOG_PAGES_IN_CHUNK_MAP_BLOCK) >> LOG_BYTES_IN_ADDRESS; 029 private static final int CHUNK_MAP_BLOCKS = 1 << 4; 030 private static final int MAX_ENTRIES_IN_CHUNK_MAP = ENTRIES_IN_CHUNK_MAP_BLOCK * CHUNK_MAP_BLOCKS; 031 private final AddressArray chunkMap = AddressArray.create(CHUNK_MAP_BLOCKS); 032 private int chunkMapLimit = -1; 033 private int chunkMapCursor = -1; 034 035 void reset() { 036 chunkMapLimit = chunkMapCursor; 037 } 038 039 public Address getHeadChunk() { 040 if (chunkMapLimit < 0) 041 return Address.zero(); 042 else 043 return getMapAddress(0).loadAddress(); 044 } 045 046 public Address getTailChunk() { 047 if (chunkMapLimit < 0) 048 return Address.zero(); 049 else 050 return getMapAddress(chunkMapLimit).loadAddress(); 051 } 052 053 void addNewChunkToMap(Address chunk) { 054 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Chunk.isAligned(chunk)); 055 if (chunkMapCursor == MAX_ENTRIES_IN_CHUNK_MAP - 1) 056 consolidateMap(); 057 chunkMapCursor++; 058 int index = getChunkIndex(chunkMapCursor); 059 int map = getChunkMap(chunkMapCursor); 060 if (map >= CHUNK_MAP_BLOCKS) { 061 Space.printUsageMB(); 062 VM.assertions.fail("Overflow of chunk map!"); 063 } 064 if (chunkMap.get(map).isZero()) { 065 Address tmp = Plan.metaDataSpace.acquire(1 << LOG_PAGES_IN_CHUNK_MAP_BLOCK); 066 if (tmp.isZero()) { 067 Space.printUsageMB(); 068 VM.assertions.fail("Failed to allocate space for chunk map. Is metadata virtual memory exhausted?"); 069 } 070 chunkMap.set(map, tmp); 071 } 072 Address entry = chunkMap.get(map).plus(index << LOG_BYTES_IN_ADDRESS); 073 entry.store(chunk); 074 Chunk.setMap(chunk, chunkMapCursor); 075 if (VM.VERIFY_ASSERTIONS) checkMap(); 076 } 077 078 void removeChunkFromMap(Address chunk) { 079 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Chunk.isAligned(chunk)); 080 int entry = Chunk.getMap(chunk); 081 getMapAddress(entry).store(Address.zero()); // zero it it 082 Chunk.setMap(chunk, -entry); 083 if (VM.VERIFY_ASSERTIONS) checkMap(); 084 } 085 086 private int getChunkIndex(int entry) { 087 return entry & (ENTRIES_IN_CHUNK_MAP_BLOCK - 1); 088 } 089 090 private int getChunkMap(int entry) { 091 return entry & ~(ENTRIES_IN_CHUNK_MAP_BLOCK - 1); 092 } 093 094 private Address getMapAddress(int entry) { 095 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(entry >= 0); 096 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(entry <= chunkMapCursor); 097 int index = getChunkIndex(entry); 098 int map = getChunkMap(entry); 099 return chunkMap.get(map).plus(index << LOG_BYTES_IN_ADDRESS); 100 } 101 102 /** 103 * A chunk iterator. Return the next chunk in sequence, or null if the 104 * next chunk is the same chunk (ie there is only one chunk in the iterator). 105 * 106 * @param chunk The chunk 107 * @return The next chunk in the sequence, or null if next is chunk. 108 */ 109 public Address nextChunk(Address chunk) { 110 return nextChunk(chunk, chunk); 111 } 112 113 /** 114 * A chunk iterator. Return the next chunk in sequence, or {@code null} if the 115 * next chunk is limit. 116 * 117 * @param chunk The chunk 118 * @param limit The starting point (if next is equal to this, we're done) 119 * @return The next chunk in the sequence, or {@code null} if next is limit. 120 */ 121 private Address nextChunk(final Address chunk, final Address limit) { 122 return nextChunk(chunk, Chunk.getMap(limit), 1); 123 } 124 125 /** 126 * A chunk iterator. Return the next chunk in sequence, strided 127 * by stride steps, or {@code null} if the next chunk is start. 128 * 129 * @param chunk The chunk 130 * @param start The point where this iterator started, which defines its end-point 131 * @param stride The stride by which the iterator should be stepped 132 * @return The next chunk in the sequence, or {@code null} if next is start. 133 */ 134 public Address nextChunk(final Address chunk, final int start, final int stride) { 135 if (VM.VERIFY_ASSERTIONS) checkMap(); 136 return nextChunk(Chunk.getMap(chunk), start, stride); 137 } 138 139 /** 140 * A chunk iterator. Return the next chunk in sequence, strided 141 * by stride steps, or {@code null} if the next chunk is start. 142 * 143 * @param entry The entry we're currently up to 144 * @param start The point where this iterator started, which defines its end-point 145 * @param stride The stride by which the iterator should be stepped 146 * @return The next chunk in the sequence, or {@code null} if next is start. 147 */ 148 private Address nextChunk(int entry, final int start, final int stride) { 149 if (VM.VERIFY_ASSERTIONS) checkMap(); 150 Address chunk; 151 do { 152 entry += stride; 153 if (entry > chunkMapLimit) { 154 entry = entry % stride; 155 } 156 chunk = getMapAddress(entry).loadAddress(); 157 } while (chunk.isZero() && entry != start); 158 return entry == start ? Address.zero() : chunk; 159 } 160 161 public Address firstChunk(int ordinal, int stride) { 162 if (ordinal > chunkMapCursor) return Address.zero(); 163 if (VM.VERIFY_ASSERTIONS) checkMap(); 164 Address chunk = getMapAddress(ordinal).loadAddress(); 165 return chunk.isZero() ? nextChunk(ordinal, ordinal, stride) : chunk; 166 } 167 168 private void checkMap() { 169 VM.assertions._assert(chunkMapLimit <= chunkMapCursor); 170 for (int entry = 0; entry <= chunkMapCursor; entry++) { 171 Address chunk = getMapAddress(entry).loadAddress(); 172 if (!chunk.isZero()) 173 VM.assertions._assert(Chunk.getMap(chunk) == entry); 174 } 175 } 176 177 public void consolidateMap() { 178 int oldCursor = 0; 179 int newCursor = -1; 180 while (oldCursor <= chunkMapCursor) { 181 Address chunk = getMapAddress(oldCursor).loadAddress(); 182 if (!chunk.isZero()) { 183 getMapAddress(++newCursor).store(chunk); 184 Chunk.setMap(chunk, newCursor); 185 } 186 oldCursor++; 187 } 188 chunkMapCursor = newCursor; 189 chunkMapLimit = newCursor; 190 if (VM.VERIFY_ASSERTIONS) checkMap(); 191 } 192}