/* * 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.utility.heap.layout; import static org.mmtk.utility.heap.layout.VMLayoutConstants.*; import org.mmtk.policy.Space; import org.mmtk.utility.Constants; import org.mmtk.utility.Conversions; import org.mmtk.utility.GenericFreeList; import org.mmtk.utility.Log; import org.mmtk.utility.RawMemoryFreeList; import org.mmtk.utility.heap.FreeListPageResource; import org.mmtk.utility.heap.SpaceDescriptor; import org.mmtk.vm.VM; import org.vmmagic.pragma.Inline; import org.vmmagic.pragma.Interruptible; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.AddressArray; import org.vmmagic.unboxed.Extent; import org.vmmagic.unboxed.Word; @Uninterruptible public final class Map64 extends Map { /** * The fraction of a space that is left after we allocate a map that maps the entire space. * <p> * Just an estimate so that we can slightly reduce the size of the map. OK if it's too large, but * too small would be bad. */ private static final double NON_MAP_FRACTION = 1 - 8.0 / 4096; private final int[] descriptorMap; private final Space[] spaceMap; private final AddressArray highWater; private final AddressArray baseAddress; private final FreeListPageResource[] flPageResources; private final RawMemoryFreeList[] flMap; private boolean finalized = false; Map64() { this.descriptorMap = new int[HeapParameters.MAX_SPACES]; this.spaceMap = new Space[HeapParameters.MAX_SPACES]; this.highWater = AddressArray.create(HeapParameters.MAX_SPACES); this.baseAddress = AddressArray.create(HeapParameters.MAX_SPACES); /* Avoid producing an Address that will blow up a 32-bit compiler */ int logSpaceSize = VM.HEAP_LAYOUT_64BIT ? HeapParameters.LOG_SPACE_SIZE_64 : 0; for (int i = 0; i < HeapParameters.MAX_SPACES; i++) { Address base = Word.fromIntZeroExtend(i).lsh(logSpaceSize).toAddress(); highWater.set(i, base); baseAddress.set(i, base); } this.flPageResources = new FreeListPageResource[HeapParameters.MAX_SPACES]; this.flMap = new RawMemoryFreeList[HeapParameters.MAX_SPACES]; } public static int spaceIndex(Address addr) { if (addr.GT(HEAP_END)) { return -1; } return addr.toWord().rshl(SPACE_SHIFT_64).toInt(); } private boolean isSpaceStart(Address base) { return base.toWord().and(SPACE_MASK_64.not()).isZero(); } @Override @Interruptible public GenericFreeList createFreeList(FreeListPageResource pr) { /* The size in units (pages) of the free list */ int units = (SPACE_SIZE_64.toWord().rshl(Constants.LOG_BYTES_IN_PAGE).toInt()); return createFreeList(pr, units, units); } @Override @Interruptible public GenericFreeList createFreeList(FreeListPageResource pr, int units, int grain) { Space space = pr.getSpace(); Address start = space.getStart(); Extent extent = space.getExtent(); int index = spaceIndex(start); units = (int) (units * NON_MAP_FRACTION); Extent listExtent = Conversions.pagesToBytes(RawMemoryFreeList.sizeInPages(units, 1)); if (VMLayoutConstants.VERBOSE_BUILD) { Log.write("Allocating free list for space "); Log.write(space.getName()); Log.write(", start = ", start); Log.write(", extent = ", extent); Log.write(", units = ", units); Log.write(" listPages = ", RawMemoryFreeList.sizeInPages(units, 1)); Log.writeln(", listExtent = ", listExtent); } RawMemoryFreeList list = new RawMemoryFreeList(start, start.plus(listExtent), units, grain); flPageResources[index] = pr; flMap[index] = list; /* Adjust the base address and highwater to account for the allocated chunks for the map */ Address base = Conversions.chunkAlign(start.plus(listExtent), false); highWater.set(index, base); baseAddress.set(index, base); return list; } /**************************************************************************** * * Map accesses and insertion */ /** * Insert a space and its descriptor into the map, associating it * with a particular address range. * * @param start The start address of the region to be associated * with this space. * @param extent The size of the region, in bytes * @param descriptor The descriptor for this space * @param space The space to be associated with this region */ @Override public void insert(Address start, Extent extent, int descriptor, Space space) { if (VM.VERIFY_ASSERTIONS) { if (!isSpaceStart(start)) { Log.write("Space "); Log.write(space.getName()); Log.write(", extent ", extent); Log.write(" starts at ", start); Log.writeln(" which is not the start of a space in the 64-bit model"); VM.assertions.fail("Space start address is wrong"); } if (VM.HEAP_LAYOUT_64BIT && !extent.LE(SPACE_SIZE_64)) { Log.write("Space "); Log.write(space.getName()); Log.write(", SPACE_SIZE=", SPACE_SIZE_64); Log.writeln(", extent=", extent); } VM.assertions._assert(VM.HEAP_LAYOUT_32BIT || extent.LE(SPACE_SIZE_64)); } final int index = spaceIndex(start); descriptorMap[index] = descriptor; VM.barriers.objectArrayStoreNoGCBarrier(spaceMap, index, space); } /** * Allocate some number of contiguous chunks within a discontiguous region. In a 64-bit * model, this involves extending a contiguous region, using 'head' as the address * of the highest chunk allocated. * * @param descriptor The descriptor for the space to which these chunks will be assigned * @param space The space to which these chunks will be assigned * @param chunks The number of chunks required * @param head The previous contiguous set of chunks for this space (to create a linked list of contiguous regions for each space) * @return The address of the assigned memory. If the request fails we return Address.zero(). */ @Override public Address allocateContiguousChunks(int descriptor, Space space, int chunks, Address head) { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(spaceIndex(space.getStart()) == SpaceDescriptor.getIndex(descriptor)); int index = SpaceDescriptor.getIndex(descriptor); Address rtn = highWater.get(index); Extent extent = Extent.fromIntZeroExtend(chunks << LOG_BYTES_IN_CHUNK); highWater.set(index, rtn.plus(extent)); /* Grow the free list to accommodate the new chunks */ RawMemoryFreeList freeList = flMap[spaceIndex(space.getStart())]; if (freeList != null) { freeList.growFreeList(Conversions.bytesToPages(extent)); int basePage = Conversions.bytesToPages(rtn.diff(baseAddress.get(index))); for (int offset = 0; offset < chunks * PAGES_IN_CHUNK; offset += PAGES_IN_CHUNK) { freeList.setUncoalescable(basePage + offset); /* The 32-bit implementation requires that pages are returned allocated to the caller */ freeList.alloc(PAGES_IN_CHUNK, basePage + offset); } } return rtn; } @Override public Address getNextContiguousRegion(Address start) { VM.assertions.fail("Discontiguous spaces are not supported in 64-bit mode"); return Address.zero(); } @Override public int getContiguousRegionChunks(Address start) { VM.assertions.fail("Discontiguous spaces are not supported in 64-bit mode"); return 0; } @Override public Extent getContiguousRegionSize(Address start) { VM.assertions.fail("Discontiguous spaces are not supported in 64-bit mode"); return Extent.zero(); } @Override public void freeAllChunks(Address anyChunk) { VM.assertions.fail("Discontiguous spaces are not supported in 64-bit mode"); } @Override public int freeContiguousChunks(Address start) { VM.assertions.fail("Discontiguous spaces are not supported in 64-bit mode"); return 0; } /** * Finalize the space map, which requires initializing all the * raw memory free lists. */ @Interruptible @Override public void finalizeStaticSpaceMap() { for (int pr = 0; pr < HeapParameters.MAX_SPACES; pr++) { if (flPageResources[pr] != null) { flPageResources[pr].resizeFreeList(Conversions.chunkAlign(flMap[pr].getLimit(), false)); } } this.finalized = true; } @Interruptible @Override public void boot() { for (int pr = 0; pr < HeapParameters.MAX_SPACES; pr++) { if (flMap[pr] != null) { flMap[pr].growFreeList(0); } } } @Override public boolean isFinalized() { return this.finalized; } /** * @param pr the resource that wants to share the discontiguous region * @return The ordinal number for a free list space wishing to share a * discontiguous region */ @Override @Interruptible public int getDiscontigFreeListPROrdinal(FreeListPageResource pr) { VM.assertions.fail("Discontiguous spaces are not supported in 64-bit mode"); return 0; } @Override public int getChunkConsumerCount() { VM.assertions.fail("Discontiguous spaces are not supported in 64-bit mode"); return 0; } @Override public int getAvailableDiscontiguousChunks() { VM.assertions.fail("Discontiguous spaces are not supported in 64-bit mode"); return 0; } /** * Return the space in which this address resides, or null if it is * outside the heap. * * @param address The address in question * @return The space in which the address resides */ @Inline @Override public Space getSpaceForAddress(Address address) { if (spaceIndex(address) < 0 || spaceIndex(address) >= spaceMap.length) { return null; } if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(0 <= spaceIndex(address) && spaceIndex(address) < spaceMap.length); return spaceMap[spaceIndex(address)]; } /** * Return the space descriptor for the space in which this object * resides. * * @param object The object in question * @return The space descriptor for the space in which the object * resides */ @Inline @Override public int getDescriptorForAddress(Address object) { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(spaceIndex(object) < descriptorMap.length); return descriptorMap[spaceIndex(object)]; } }