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