/* * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.max.vm.heap.gcx; import com.sun.max.annotate.*; import com.sun.max.unsafe.*; import com.sun.max.vm.*; import com.sun.max.vm.heap.*; import com.sun.max.vm.heap.HeapScheme.GCRequest; import com.sun.max.vm.runtime.*; /** * A simple nursery implementation that allocates objects in a single contiguous space and evacuate all survivors to the next generation on minor collections. * The next generation is responsible for keeping a reserve large enough to accommodate the worst-case evacuation. */ public final class NoAgingRegionalizedNursery implements HeapSpace { final class NurseryRefiller extends Refiller { @Override public Address allocateRefill(Size requestedSize, Pointer startOfSpaceLeft, Size spaceLeft) { GCRequest.setGCRequest(requestedSize); if (!Heap.collectGarbage()) { throw new OutOfMemoryError(); } // We're out of safepoint. The current thread hold the refill lock and will do the refill of the allocator. return Address.zero(); } @Override protected void doBeforeGC() { // Nothing to do. } @Override public Address allocateLargeRaw(Size size) { FatalError.unimplemented(); return Address.zero(); } } /** * The heap account space for this nursery is allocated from. */ private final HeapAccount<? extends HeapAccountOwner> heapAccount; private final int regionTag; /** * List of region allocated to the nursery. */ private HeapRegionList nurseryRegionsList; /** * List of regions allocated to the nursery but uncommitted. */ private HeapRegionList uncommitedNurseryRegionsList; /** * Atomic bump pointer allocator over the nursery space. The current bounds and size of the nursery are obtained from the allocator's start and end addresses. */ @INSPECTED private final AtomicBumpPointerAllocator<NurseryRefiller> allocator = new AtomicBumpPointerAllocator<NurseryRefiller>(new NurseryRefiller()); private final SpaceBounds bounds; public NoAgingRegionalizedNursery(HeapAccount<? extends HeapAccountOwner> heapAccount, int regionTag) { this.heapAccount = heapAccount; this.regionTag = regionTag; this.bounds = new SpaceBounds() { @Override Address lowestAddress() { return allocator.start(); } @Override boolean isIn(Address address) { return address.greaterEqual(lowestAddress()) && address.lessEqual(highestAddress()); } @Override boolean isContiguous() { return true; } @Override Address highestAddress() { return allocator.hardLimit(); } }; } public NoAgingRegionalizedNursery(HeapAccount<? extends HeapAccountOwner> heapAccount) { this(heapAccount, 0); } public void initialize(GenHeapSizingPolicy genSizingPolicy) { nurseryRegionsList = HeapRegionList.RegionListUse.OWNERSHIP.createList(); uncommitedNurseryRegionsList = HeapRegionList.RegionListUse.OWNERSHIP.createList(); if (!heapAccount.allocateContiguous(HeapRegionConstants.numberOfRegions(genSizingPolicy.maxYoungGenSize()), nurseryRegionsList, false, false, regionTag)) { FatalError.unexpected("Couldn't allocate contiguous range to the nursery"); } int regionID = nurseryRegionsList.head(); int numCommittedRegions = HeapRegionConstants.numberOfRegions(genSizingPolicy.initialYoungGenSize()); heapAccount.commit(RegionRange.from(regionID, numCommittedRegions)); int lastCommittedRegion = regionID + numCommittedRegions - 1; while (nurseryRegionsList.tail() != lastCommittedRegion) { uncommitedNurseryRegionsList.prepend(nurseryRegionsList.removeTail()); } allocator.initialize(RegionTable.theRegionTable().regionAddress(nurseryRegionsList.head()), genSizingPolicy.initialYoungGenSize(), Size.fromInt(HeapRegionConstants.regionSizeInBytes)); } public Pointer allocate(Size size) { return allocator.allocateCleared(size); } @Override public Size increaseSize(Size delta) { // TODO FatalError.unimplemented(); return Size.zero(); } @Override public Size decreaseSize(Size delta) { // TODO FatalError.unimplemented(); return Size.zero(); } @Override public Size totalSpace() { return allocator.size(); } @Override public Size capacity() { return Size.fromInt(HeapRegionConstants.regionSizeInBytes).times(uncommitedNurseryRegionsList.size()).plus(allocator.size()); } @Override public Pointer allocateTLAB(Size size) { final Pointer tlab = allocator.allocateRaw(size); HeapFreeChunk.format(tlab, size); return tlab; } public void retireTLAB(Pointer start, Size size) { FatalError.check(allocator.inCurrentContiguousChunk(start), "Retired TLAB Space must be in allocating space"); if (!allocator.retireTop(start, size)) { DarkMatter.format(start, size); } } @Override public boolean contains(Address address) { return allocator.inCurrentContiguousChunk(address); } @Override public void doBeforeGC() { allocator.doBeforeGC(); } @Override public void doAfterGC() { if (MaxineVM.isDebug()) { allocator.zap(); } allocator.reset(); } @Override public Size freeSpace() { return allocator.freeSpace(); } @Override public Size usedSpace() { return allocator.usedSpace(); } @Override public void visit(CellRangeVisitor visitor) { visitor.visitCells(allocator.start(), allocator.top); } @Override public SpaceBounds bounds() { return bounds; } }