Package org.jnode.vm.memmgr.def

Source Code of org.jnode.vm.memmgr.def.GCMarkVisitor

/*
* $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.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.annotation.NoInline;
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.pragma.Uninterruptible;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.ObjectReference;
import org.vmmagic.unboxed.Offset;
import org.vmmagic.unboxed.Word;

/**
* @author epr
*/
@MagicPermission
final class GCMarkVisitor extends ObjectVisitor implements ObjectFlags,
    Uninterruptible {

    /**
     * The marking stack
     */
    private final GCStack stack;

    /**
     * The number of marked objects.
     */
    private int markedObjects;

    /**
     * If true, all white and grey objects will be marked, otherwise only the
     * grey objects will be marked
     */
    private boolean rootSet;

    private final BaseVmArchitecture arch;

//    private final int slotSize;

    private final DefaultHeapManager heapManager;

    private final HeapHelper helper;

//    private final ProcessChildVisitor processChildVisitor = new ProcessChildVisitor();

    /**
     * Create a new instance
     *
     * @param stack
     */
    public GCMarkVisitor(DefaultHeapManager heapManager, BaseVmArchitecture arch,
                         GCStack stack) {
        this.heapManager = heapManager;
        this.stack = stack;
        this.markedObjects = 0;
        this.rootSet = false;
        this.arch = arch;
        this.helper = heapManager.getHelper();
//        this.slotSize = arch.getReferenceSize();
    }

    /**
     * @param object
     * @return boolean
     * @see org.jnode.vm.facade.ObjectVisitor#visit(java.lang.Object)
     */
    public boolean visit(Object object) {

        // Check the current color first, since a stackoverflow of
        // the mark stack results in another iteration of visits.
        final int gcColor = VmMagic.getObjectColor(object);
        if (gcColor == GC_BLACK) {
            return true;
        } else if (rootSet || (gcColor == GC_GREY)) {
            switch (gcColor) {
                case GC_YELLOW:

                    //Avoid telling such stories in a garbage collector!!!
                    //Unsafe.debug("Yellow Object in the rootset.\n");
                    //Unsafe.debug("Perhaps corrupted Heap or bad luck.\n");
                    //Unsafe.debug("Continue as long as we don't have a");
                    //Unsafe.debug("gc map for the stack.\n Panic JNode once");
                    //Unsafe.debug("we have an exact GC.\n");

                    //Unsafe.die("Corrupted Heap\n");
                    return true;
                case GC_WHITE: {
                    final boolean ok;
                    ok = helper.atomicChangeObjectColor(object, gcColor,
                        GC_GREY);
                    if (!ok) {
                        Unsafe.debug("Could not change object color. ");
                    }
                    break;
                }               
                case GC_GREY:
                    break;
                default: {
                    Unsafe.debug("color");
                    Unsafe.debug(gcColor);
                    helper.die("Unknown GC color on object");
                }
            }
            stack.push(object);
            mark();
        }

        final boolean rc = (!stack.isOverflow());
        return rc;
    }

    /**
     * Reset this visitor to its original state.
     */
    @Inline
    public void reset() {
        this.markedObjects = 0;
    }

    /**
     * Process all objects on the markstack, until the markstack is empty.
     */
    @NoInline
    protected final void mark() {
        while (!stack.isEmpty()) {
            final Object object = stack.pop();
            markedObjects++;
            VmType vmClass;
            try {
                vmClass = VmMagic.getObjectType(object);
            } catch (NullPointerException ex) {
                // This is a symptom of heap corruption
                if (object == null) {
                    helper.die("GCMarkError: null object");
                } else {
                    final Address objAddr = ObjectReference.fromObject(object).toAddress();
                    Unsafe.debug("Object address is ");
                    Unsafe.debug(objAddr);
                    Unsafe.debug(", tib is ");
                    Object[] tib = VmMagic.getTIB(object);
                    Unsafe.debug(ObjectReference.fromObject(tib).toAddress());
                    Unsafe.debug(", flags word is ");
                    Word flags = VmMagic.getObjectFlags(object);
                    Unsafe.debug(flags);
                    Unsafe.debug(", markedObjects is ");
                    Unsafe.debug(markedObjects);
                    Unsafe.debug('\n');
                    helper.die("GCMarkError: NPE");
                }
                throw ex;
            }
            if (vmClass == null) {
                Unsafe.debug("Oops vmClass == null in (");
                Unsafe.debug(markedObjects);
                Unsafe.debug(")");
                helper.die("vmClass == null in mark()");
            } else if (vmClass.isArray()) {
                if (!vmClass.isPrimitiveArray()) {
                    markArray(object);
                }
            } else {
                markObject(object, (VmNormalClass) vmClass);
            }
            processChild(VmMagic.getTIB(object));
            final Monitor monitor = helper.getInflatedMonitor(object, arch);
            if (monitor != null) {
                processChild(monitor);
            }
            final int gcColor = VmMagic.getObjectColor(object);
            helper.atomicChangeObjectColor(object, gcColor, GC_BLACK);
        }
    }

    /**
     * Mark all elements in the given array. The array must contain references
     * only.
     *
     * @param object
     */
    @Inline
    private void markArray(Object object) {
        try {
            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) {
                    // Enable the following in the case of heap corruption
                    if (true) {
                        verifyChild(child, object, "array child", i, i);
                    }
                   
                    processChild(child);
                }
            }
        } catch (ClassCastException ex) {
            System.out.println("object.class=" + object.getClass().getName());
            throw ex;
        }
    }

    /**
     * Mark all instance variables of the given object.
     *
     * @param object
     * @param vmClass
     */
    @Inline
    private void markObject(Object object, VmNormalClass vmClass) {
        final int[] referenceOffsets = vmClass.getReferenceOffsets();
        final int cnt = referenceOffsets.length;
        if (cnt == 0) {
            return;
        }

        final int size = vmClass.getObjectSize();
        final Address objAddr = ObjectReference.fromObject(object).toAddress();

        for (int i = 0; i < cnt; i++) {
            final 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 ObjectReference child = objAddr.loadObjectReference(Offset.fromIntZeroExtend(offset));
                if (child != null) {
                    // Enable the following in the case of heap corruption
                    if (false) {
                        verifyChild(child, object, "object child", i, offset);
                    }
                   
                    processChild(child);
                }
            }
        }
    }

    @Inline
    private final void verifyChild(Object child, Object parent, String where, int i, int offset) {
        if (child != null) {
            final ObjectReference childRef = ObjectReference.fromObject(child);
            if (!heapManager.isObject(childRef.toAddress())) {
                Unsafe.debug("GCMarkError: in ");
                Unsafe.debug(where);
                Unsafe.debug(", i ");
                Unsafe.debug(i);
                Unsafe.debug(", offset ");
                Unsafe.debug(offset);
                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));
                helper.die("Corrupted heap");
            }
        }
    }

    /**
     * Process a child of an object (this child is a reference).
     *
     * @param child
     */
    @Inline
    final void processChild(Object child) {
        final int gcColor = VmMagic.getObjectColor(child);
        if (gcColor <= GC_WHITE) {
            // Yellow or White
            helper.atomicChangeObjectColor(child, gcColor, GC_GREY);
            try {
                // TEST for a valid vmclass.
                stack.push(child);
            } catch (NullPointerException ex) {
                Unsafe.debug("\nObject address ");
                Unsafe.debug(ObjectReference.fromObject(child).toAddress().toInt());
                Unsafe.debug("\nObject TIB ");
                Unsafe.debug(ObjectReference.fromObject(VmMagic.getTIB(child)).toAddress().toInt());
                helper.die("NPE in processChild; probably corrupted heap");
            }
        }
    }

    /**
     * Gets the number of objects marked by this visitor.
     *
     * @return int
     */
    @Inline
    public int getMarkedObjects() {
        return markedObjects;
    }

    /**
     * Gets the rootSet attribute.
     *
     * @return boolean
     */
    @Inline
    public boolean isRootSet() {
        return rootSet;
    }

    /**
     * Sets the rootSet attribute.
     *
     * @param b If true, all white and grey objects will be marked, otherwise
     *          only the grey objects will be marked.
     */
    @Inline
    public void setRootSet(boolean b) {
        rootSet = b;
    }
}
TOP

Related Classes of org.jnode.vm.memmgr.def.GCMarkVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.