/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.vm;
import org.jnode.annotation.MagicPermission;
import org.jnode.annotation.Uninterruptible;
import org.jnode.vm.classmgr.ObjectFlags;
import org.jnode.vm.classmgr.ObjectLayout;
import org.jnode.vm.classmgr.VmMethod;
import org.jnode.vm.facade.ObjectVisitor;
import org.jnode.vm.facade.VmThread;
import org.jnode.vm.facade.VmThreadVisitor;
import org.jnode.vm.facade.VmUtils;
import org.jnode.vm.isolate.VmIsolate;
import org.jnode.vm.memmgr.HeapHelper;
import org.jnode.vm.memmgr.VmHeapManager;
import org.jnode.vm.scheduler.Monitor;
import org.jnode.vm.scheduler.MonitorManager;
import org.jnode.vm.scheduler.VmProcessor;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Extent;
import org.vmmagic.unboxed.ObjectReference;
import org.vmmagic.unboxed.Word;
/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
@MagicPermission
@Uninterruptible
final class HeapHelperImpl extends HeapHelper {
private static final class ThreadRootVisitor implements VmThreadVisitor {
private VmHeapManager heapManager;
private ObjectVisitor visitor;
public final void initialize(ObjectVisitor visitor,
VmHeapManager heapManager) {
this.visitor = visitor;
this.heapManager = heapManager;
}
public boolean visit(VmThread thread) {
return thread.accept(visitor, heapManager);
}
}
private final int flagsOffset;
private final ThreadRootVisitor threadRootVisitor;
/**
* Initialize this instance.
*
* @param arch
*/
public HeapHelperImpl(BaseVmArchitecture arch) {
if (VmUtils.getVm() != null) {
throw new SecurityException(
"Cannot instantiate HeapHelpImpl at runtime");
}
final int refSize = arch.getReferenceSize();
flagsOffset = ObjectLayout.FLAGS_SLOT * refSize;
this.threadRootVisitor = new ThreadRootVisitor();
}
/**
* @see org.jnode.vm.memmgr.HeapHelper#allocateBlock(Extent)
*/
public final Address allocateBlock(Extent size) {
return MemoryBlockManager.allocateBlock(size);
}
/**
* Change the color of the given object from oldColor to newColor.
*
* @param dst
* @param oldColor
* @param newColor
* @return True if the color was changed, false if the current color of the
* object was not equal to oldColor.
*/
public boolean atomicChangeObjectColor(Object dst, int oldColor,
int newColor) {
final Address addr = ObjectReference.fromObject(dst).toAddress().add(
flagsOffset);
for (;;) {
Word oldValue = addr.prepareWord();
if (oldValue
.and(Word.fromIntZeroExtend(ObjectFlags.GC_COLOUR_MASK))
.NE(Word.fromIntZeroExtend(oldColor))) {
return false;
}
Word newValue = oldValue.and(
Word.fromIntZeroExtend(ObjectFlags.GC_COLOUR_MASK).not())
.or(Word.fromIntZeroExtend(newColor));
if (addr.attempt(oldValue, newValue)) {
return true;
}
}
}
/**
* @see org.jnode.vm.memmgr.HeapHelper#clear(Address, Extent)
*/
public final void clear(Address dst, Extent size) {
Unsafe.clear(dst, size);
}
/**
* @see org.jnode.vm.memmgr.HeapHelper#clear(Address, int)
*/
public final void clear(Address dst, int size) {
Unsafe.clear(dst, Extent.fromIntSignExtend(size));
}
/**
* @see org.jnode.vm.memmgr.HeapHelper#copy(Address, Address, int)
*/
public final void copy(Address src, Address dst, Extent size) {
Unsafe.copy(src, dst, size);
}
/**
* @see org.jnode.vm.memmgr.HeapHelper#die(java.lang.String)
*/
public final void die(String msg) {
try {
VmProcessor.current().getArchitecture().getStackReader()
.debugStackTrace();
} finally {
Unsafe.die(msg);
}
}
/**
* @see org.jnode.vm.memmgr.HeapHelper#getBootHeapEnd()
*/
public final Address getBootHeapEnd() {
return Unsafe.getBootHeapEnd();
}
/**
* @see org.jnode.vm.memmgr.HeapHelper#getBootHeapStart()
*/
public final Address getBootHeapStart() {
return Unsafe.getBootHeapStart();
}
/**
* @see org.jnode.vm.memmgr.HeapHelper#getBootImageEnd()
*/
public final Address getBootImageEnd() {
return Unsafe.getBootHeapEnd();
}
/**
* @see org.jnode.vm.memmgr.HeapHelper#getBootImageStart()
*/
public final Address getBootImageStart() {
return Unsafe.getKernelStart();
}
/**
* @see org.jnode.vm.memmgr.HeapHelper#getHeapSize()
*/
public Extent getHeapSize() {
final Word end = Unsafe.getMemoryEnd().toWord();
final Word start = Unsafe.getMemoryStart().toWord();
return end.sub(start).toExtent();
}
/**
* @see org.jnode.vm.memmgr.HeapHelper#getInflatedMonitor(java.lang.Object,
* org.jnode.vm.BaseVmArchitecture)
*/
public final Monitor getInflatedMonitor(Object object, BaseVmArchitecture arch) {
return MonitorManager.getInflatedMonitor(object);
}
/**
* @see org.jnode.vm.memmgr.HeapHelper#invokeFinalizer(org.jnode.vm.classmgr.VmMethod,
* java.lang.Object)
*/
public final void invokeFinalizer(VmMethod finalizer, Object object) {
Unsafe.pushObject(object);
Unsafe.invokeVoid(finalizer);
}
/**
* Unblock all threads (on all processors). This method is called after a
* call a call to {@link #stopThreadsAtSafePoint()}.
*/
public void restartThreads() {
VmMagic.currentProcessor().enableReschedule(true);
}
/**
* Mark the given object as finalized.
*
* @param dst
*/
public final void setFinalized(Object dst) {
final Address addr = ObjectReference.fromObject(dst).toAddress().add(
flagsOffset);
int oldValue;
int newValue;
do {
oldValue = addr.prepareInt();
if ((oldValue & ObjectFlags.STATUS_FINALIZED) != 0) {
return;
}
newValue = oldValue | ObjectFlags.STATUS_FINALIZED;
} while (!addr.attempt(oldValue, newValue));
// } while (!Unsafe.atomicCompareAndSwap(addr, oldValue, newValue));
}
/**
* Stop and block all threads (on all processors) on a GC safe point. Only
* the calling thread (the GC thread) will continue.
*/
public final void stopThreadsAtSafePoint() {
VmMagic.currentProcessor().disableReschedule(true);
}
/**
* Visit all roots of the object tree.
*
* @param visitor
*/
public void visitAllRoots(ObjectVisitor visitor, VmHeapManager heapManager) {
final org.jnode.vm.facade.Vm vm = VmUtils.getVm();
if (!vm.getSharedStatics().walk(visitor)) {
return;
}
if (!VmProcessor.current().getIsolatedStatics().walk(visitor)) {
return;
}
if (!VmIsolate.walkIsolates(visitor)) {
return;
}
threadRootVisitor.initialize(visitor, heapManager);
VmMagic.currentProcessor().getScheduler().visitAllThreads(threadRootVisitor);
}
/**
* @see org.jnode.vm.memmgr.HeapHelper#bootArchitecture(boolean)
*/
public final void bootArchitecture(boolean emptyMMap) {
((BaseVmArchitecture) VmUtils.getVm().getArch()).boot(emptyMMap);
}
}