/*
* Copyright (c) 2013, 2017, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.oracle.svm.core.genscavenge;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.word.Pointer;
import org.graalvm.word.WordFactory;
import com.oracle.svm.core.annotate.AlwaysInline;
import com.oracle.svm.core.annotate.NeverInline;
import com.oracle.svm.core.log.Log;
import com.oracle.svm.core.util.VMError;
Apply an ObjectVisitor to all the new Objects in a Space since a snapshot.
This knows that allocations take place from the last HeapChunks of the Space. And it knows (too
much about) that AlignedChunks have a top pointer.
/**
* Apply an ObjectVisitor to all the new Objects in a Space since a snapshot.
*
* This knows that allocations take place from the last HeapChunks of the Space. And it knows (too
* much about) that AlignedChunks have a top pointer.
*/
final class GreyObjectsWalker {
The Space that is being captured. /** The Space that is being captured. */
private Space space;
/* The top of the Space during capture. */
private AlignedHeapChunk.AlignedHeader alignedHeapChunk;
private Pointer alignedTop;
private UnalignedHeapChunk.UnalignedHeader unalignedHeapChunk;
@Platforms(Platform.HOSTED_ONLY.class)
GreyObjectsWalker() {
}
Take a snapshot of a Space, such that all Objects in the Space are now black, and any new
Objects in the Space will be grey, and can have an ObjectVisitor applied to them.
/**
* Take a snapshot of a Space, such that all Objects in the Space are now black, and any new
* Objects in the Space will be grey, and can have an ObjectVisitor applied to them.
*/
void setScanStart(Space s) {
Log trace = Log.noopLog().string("[Space.GreyObjectsWalker.setScanStart:").string(" s: ").string(s.getName());
space = s;
AlignedHeapChunk.AlignedHeader aChunk = s.getLastAlignedHeapChunk();
alignedHeapChunk = aChunk;
trace.string(" alignedHeapChunk: ").hex(alignedHeapChunk).string(" isNull: ").bool(aChunk.isNull());
alignedTop = (aChunk.isNonNull() ? HeapChunk.getTopPointer(aChunk) : WordFactory.nullPointer());
trace.string(" alignedTop: ").hex(alignedTop);
unalignedHeapChunk = s.getLastUnalignedHeapChunk();
trace.string(" unalignedChunkPointer: ").hex(unalignedHeapChunk).string("]").newline();
}
Compare the snapshot to the current state of the Space to see if there are grey Objects. /** Compare the snapshot to the current state of the Space to see if there are grey Objects. */
@AlwaysInline("GC performance")
boolean haveGreyObjects() {
return alignedHeapChunk.notEqual(space.getLastAlignedHeapChunk()) || alignedHeapChunk.isNonNull() && alignedTop.notEqual(HeapChunk.getTopPointer(alignedHeapChunk)) ||
unalignedHeapChunk.notEqual(space.getLastUnalignedHeapChunk());
}
@NeverInline("Split the GC into reasonable compilation units")
void walkGreyObjects() {
while (haveGreyObjects()) {
walkAlignedGreyObjects();
walkUnalignedGreyObjects();
}
}
@AlwaysInline("GC performance")
private void walkAlignedGreyObjects() {
AlignedHeapChunk.AlignedHeader aChunk;
if (alignedHeapChunk.isNull() && alignedTop.isNull()) {
/* If the snapshot is empty, then I have to walk from the beginning of the Space. */
aChunk = space.getFirstAlignedHeapChunk();
} else {
/* Otherwise walk Objects that arrived after the snapshot. */
aChunk = alignedHeapChunk;
}
/* Visit Objects in the AlignedChunks. */
GreyToBlackObjectVisitor visitor = GCImpl.getGCImpl().getGreyToBlackObjectVisitor();
if (aChunk.isNonNull()) {
AlignedHeapChunk.AlignedHeader lastChunk;
do {
lastChunk = aChunk;
if (!AlignedHeapChunk.walkObjectsInline(aChunk, visitor)) {
throw VMError.shouldNotReachHere();
}
aChunk = HeapChunk.getNext(aChunk);
} while (aChunk.isNonNull());
/* Move the scan point. */
alignedHeapChunk = lastChunk;
alignedTop = HeapChunk.getTopPointer(lastChunk);
}
}
@AlwaysInline("GC performance")
private void walkUnalignedGreyObjects() {
/* Visit the Objects in the UnalignedChunk after the snapshot UnalignedChunk. */
UnalignedHeapChunk.UnalignedHeader uChunk;
if (unalignedHeapChunk.isNull()) {
uChunk = space.getFirstUnalignedHeapChunk();
} else {
uChunk = HeapChunk.getNext(unalignedHeapChunk);
}
GreyToBlackObjectVisitor visitor = GCImpl.getGCImpl().getGreyToBlackObjectVisitor();
if (uChunk.isNonNull()) {
UnalignedHeapChunk.UnalignedHeader lastChunk;
do {
lastChunk = uChunk;
if (!UnalignedHeapChunk.walkObjectsInline(uChunk, visitor)) {
throw VMError.shouldNotReachHere();
}
uChunk = HeapChunk.getNext(uChunk);
} while (uChunk.isNonNull());
/* Move the scan point. */
unalignedHeapChunk = lastChunk;
}
}
}