/* * $Id$ * * Copyright (C) 2003-2015 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.memmgr.def; import org.jnode.vm.Unsafe; import org.jnode.vm.BaseVmArchitecture; import org.jnode.vm.VmMagic; import org.jnode.annotation.Inline; import org.jnode.annotation.MagicPermission; import org.jnode.vm.classmgr.ObjectFlags; import org.jnode.vm.classmgr.VmNormalClass; import org.jnode.vm.classmgr.VmType; import org.jnode.vm.facade.ObjectVisitor; import org.jnode.vm.memmgr.HeapHelper; import org.jnode.vm.scheduler.Monitor; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.ObjectReference; import org.vmmagic.unboxed.Offset; /** * @author Ewout Prangsma (epr@users.sourceforge.net) */ @MagicPermission final class GCVerifyVisitor extends ObjectVisitor { private final HeapHelper helper; private final DefaultHeapManager heapManager; private final BaseVmArchitecture arch; private int errorCount; public GCVerifyVisitor(DefaultHeapManager heapManager, BaseVmArchitecture arch) { this.helper = heapManager.getHelper(); this.heapManager = heapManager; this.arch = arch; } public final void reset() { errorCount = 0; } /** * @see org.jnode.vm.facade.ObjectVisitor#visit(java.lang.Object) */ public final boolean visit(Object object) { final int color = VmMagic.getObjectColor(object); if (color == ObjectFlags.GC_YELLOW) { // Ignore objects that need to be finalized. return true; } if (VmMagic.isFinalized(object)) { // Ignore finalized objects that need to be freed return true; } VmType vmClass; try { vmClass = VmMagic.getObjectType(object); } catch (NullPointerException ex) { if (object == null) { helper.die("GCVerifyError: null object"); } else if (VmMagic.getTIB(object) == null) { helper.die("GCVerifyError: null TIB"); } else { helper.die("GCVerifyError: other NPE"); } /* not reached */ throw ex; } if (vmClass == null) { helper.die("GCVerifyError: vmClass"); } else if (vmClass.isArray()) { if (!vmClass.isPrimitiveArray()) { verifyArray(object); } } else { verifyObject(object, (VmNormalClass) vmClass); } verifyChild(VmMagic.getTIB(object), object, "tib"); final Monitor monitor = helper.getInflatedMonitor(object, arch); if (monitor != null) { verifyChild(monitor, object, "monitor"); } return (errorCount == 0); } @Inline private final void verifyArray(Object object) { final Object[] arr = (Object[]) object; final int length = arr.length; for (int i = 0; i < length; i++) { final Object child = arr[i]; if (child != null) { verifyChild(child, object, "Object[]"); } } } @Inline private final void verifyObject(Object object, VmNormalClass<?> vmClass) { final int[] referenceOffsets = vmClass.getReferenceOffsets(); final int cnt = referenceOffsets.length; final int size = vmClass.getObjectSize(); final Address ptr = ObjectReference.fromObject(object).toAddress(); for (int i = 0; i < cnt; i++) { int offset = referenceOffsets[i]; if ((offset < 0) || (offset >= size)) { Unsafe.debug("reference offset out of range!"); Unsafe.debug(vmClass.getName()); helper.die("Class internal error"); } else { final Object child = ptr.loadObjectReference(Offset.fromIntZeroExtend(offset)).toObject(); if (child != null) { verifyChild(child, object, "object child"); } } } } @Inline private final void verifyChild(Object child, Object parent, String where) { if (child != null) { final ObjectReference childRef = ObjectReference.fromObject(child); if (!heapManager.isObject(childRef.toAddress())) { Unsafe.debug("GCVerifyError: in "); Unsafe.debug(where); Unsafe.debug(", parent type "); Unsafe.debug(VmMagic.getObjectType(parent).getName()); Unsafe.debug(VmMagic.getObjectColor(parent)); Unsafe.debug("; child ("); Unsafe.debug(childRef.toAddress().toInt()); Unsafe.debug(") is not an object "); Unsafe.debug(VmMagic.getObjectColor(childRef)); errorCount++; } } } /** * @return Returns the errorCount. */ public final int getErrorCount() { return this.errorCount; } }