/* * Copyright (c) 2010, 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 static com.sun.max.vm.intrinsics.MaxineIntrinsicIDs.*; import com.sun.max.annotate.*; import com.sun.max.unsafe.*; import com.sun.max.vm.*; import com.sun.max.vm.actor.holder.*; import com.sun.max.vm.layout.*; import com.sun.max.vm.reference.*; import com.sun.max.vm.runtime.*; import com.sun.max.vm.type.*; /** * A Circular doubly linked list of free heap chunk. * Ease fast insertion and removal. */ public class DLinkedHeapFreeChunk extends HeapFreeChunk { public static final DynamicHub DLINKED_HEAP_FREE_CHUNK_HUB = ClassActor.fromJava(DLinkedHeapFreeChunk.class).dynamicHub(); /** * Index of the word storing "prev" field of the heap free chunk. */ private static final int PREV_INDEX; static { PREV_INDEX = ClassRegistry.findField(DLinkedHeapFreeChunk.class, "prev").offset() >> Word.widthValue().log2numberOfBytes; } @INLINE public static Address getFreeChunkPrev(Address chunkAddress) { return chunkAddress.asPointer().getWord(PREV_INDEX).asAddress(); } @INLINE public static void setFreeChunkPrev(Address chunkAddress, Address prevChunkAddress) { chunkAddress.asPointer().setWord(PREV_INDEX, prevChunkAddress); } @INTRINSIC(UNSAFE_CAST) private static native DLinkedHeapFreeChunk asDLinkedHeapFreeChunk(Object freeChunk); @INLINE private DLinkedHeapFreeChunk next() { return asDLinkedHeapFreeChunk(next); } @INLINE static Address from(DLinkedHeapFreeChunk chunk) { return Layout.originToCell(Reference.fromJava(chunk).toOrigin()); } @INLINE public static DLinkedHeapFreeChunk to(Address address) { return asDLinkedHeapFreeChunk(Reference.fromOrigin(Layout.cellToOrigin(address.asPointer())).toJava()); } static DLinkedHeapFreeChunk format(DynamicHub hub, Address deadSpace, Size numBytes, Address nextChunk, Address prevChunk) { if (MaxineVM.isDebug()) { FatalError.check(hub.isSubClassHub(heapFreeChunkHub().classActor), "Should format with a sub-class of HeapFreeChunk"); } HeapFreeChunk.format(deadSpace, numBytes, nextChunk, hub); setFreeChunkPrev(deadSpace, prevChunk); return to(deadSpace); } /** * Format dead space into a free chunk. * @param deadSpace pointer to the first word of the dead space * @param numBytes size of the dead space in bytes * @param nextChunk address to the next {@link DLinkedHeapFreeChunk} in the free list * @param prevChunk address to the previous {@link DLinkedHeapFreeChunk} in the free list * @return a reference to HeapFreeChunk object just planted at the beginning of the free chunk. */ static DLinkedHeapFreeChunk format(Address deadSpace, Size numBytes, Address nextChunk, Address prevChunk) { return format(DLINKED_HEAP_FREE_CHUNK_HUB, deadSpace, numBytes, nextChunk, prevChunk); } public static DLinkedHeapFreeChunk format(Address deadSpace, Size numBytes) { return format(deadSpace, numBytes, Address.zero(), Address.zero()); } /** * Unlink the chunk off it's doubly linked list and return the next block. * @param dlinkedChunkAddress */ public static Address unlink(Pointer dlinkedChunkAddress) { DLinkedHeapFreeChunk chunk = asDLinkedHeapFreeChunk(Reference.fromOrigin(dlinkedChunkAddress)); DLinkedHeapFreeChunk nextChunk = asDLinkedHeapFreeChunk(chunk.next); chunk.prev.next = nextChunk; nextChunk.prev = chunk.prev; return fromHeapFreeChunk(nextChunk); } public static Pointer removeHead(Pointer listHead) { Pointer head = listHead.getWord().asPointer(); if (!head.isZero()) { DLinkedHeapFreeChunk newHead = asDLinkedHeapFreeChunk(Reference.fromOrigin(head)).next(); newHead.prev = null; listHead.setWord(from(newHead)); } return head; } /** * Remove chunk from linked list headed by cell specified in argument. * @param listHead pointer to the location holding the head of the linked list. * @param dlinkedChunkAddress */ public static Address unlink(Pointer listHead, Pointer dlinkedChunkAddress) { DLinkedHeapFreeChunk chunk = asDLinkedHeapFreeChunk(Reference.fromOrigin(dlinkedChunkAddress)); if (chunk.next == null) { listHead.setWord(Address.zero()); return Address.zero(); } Address nextChunk = unlink(dlinkedChunkAddress); if (listHead.getWord().equals(dlinkedChunkAddress)) { listHead.setWord(nextChunk); } return nextChunk; } public static boolean isDLinkedHeapFreeChunk(Pointer cell) { return Layout.readHubReference(cell).equals(DLINKED_HEAP_FREE_CHUNK_HUB); } /** * Truncate the specified chunk to the left, and return the resulting chunk. * * @param chunk pointer to the chunk to truncate * @param size size the chunk is shortened by on its left * @return chunk.plus(size) */ public static Pointer truncateLeft(Pointer chunk, Size size) { DLinkedHeapFreeChunk before = asDLinkedHeapFreeChunk(Reference.fromOrigin(chunk)); DLinkedHeapFreeChunk after = format(chunk.plus(size), before.size.minus(size)); DLinkedHeapFreeChunk next = before.next(); if (next != null) { after.next = next; next.prev = after; } if (before.prev != null) { after.prev = before.prev; before.prev.next = after; } return from(after).asPointer(); } void insertBefore(DLinkedHeapFreeChunk chunk) { chunk.next = this; chunk.prev = prev; prev.next = chunk; prev = chunk; } public static void insertUnformattedBefore(Pointer listHead, Address address, Size size) { Pointer first = listHead.getWord().asPointer(); if (first.isZero()) { format(address, size, address, address); listHead.setWord(address); } else { DLinkedHeapFreeChunk headOfList = asDLinkedHeapFreeChunk(Reference.fromOrigin(first)); headOfList.insertBefore(format(address, size)); } } DLinkedHeapFreeChunk prev; }