gcmarkvisitor.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 270 行

JAVA
270
字号
/*
 * $Id: GCMarkVisitor.java,v 1.5 2004/02/18 06:59:20 epr Exp $
 */
package org.jnode.vm.memmgr.def;

import org.jnode.vm.Address;
import org.jnode.vm.Monitor;
import org.jnode.vm.ObjectVisitor;
import org.jnode.vm.Uninterruptible;
import org.jnode.vm.Unsafe;
import org.jnode.vm.VmArchitecture;
import org.jnode.vm.VmThread;
import org.jnode.vm.classmgr.ObjectFlags;
import org.jnode.vm.classmgr.VmArrayClass;
import org.jnode.vm.classmgr.VmNormalClass;
import org.jnode.vm.classmgr.VmType;
import org.jnode.vm.memmgr.HeapHelper;

/**
 * @author epr
 */
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 VmArchitecture arch;

    private final int slotSize;

    private final DefaultHeapManager heapManager;

    private final HeapHelper helper;

    /**
     * Create a new instance
     * 
     * @param stack
     */
    public GCMarkVisitor(DefaultHeapManager heapManager, VmArchitecture 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
     * @see org.jnode.vm.ObjectVisitor#visit(java.lang.Object)
     * @return boolean
     */
    public boolean visit(Object object) {

        // Be very paranoia for now
        /*
         * if (!heapManager.isObject(helper.addressOf(object))) {
         * Unsafe.debug("visit got non-object");
         * Unsafe.debug(helper.addressToLong(helper.addressOf(object)));
         * Unsafe.getCurrentProcessor().getArchitecture().getStackReader()
         * .debugStackTrace(); helper.die("Internal error"); return false;
         */

        //testObject(object, Unsafe.getVmClass(object));
        // Check the current color first, since a stackoverflow of
        // the mark stack results in another iteration of visits.
        final int gcColor = helper.getObjectColor(object);
        if (gcColor == GC_BLACK) {
            return true;
        } else if (rootSet || (gcColor == GC_GREY)) {
            switch (gcColor) {
            case GC_WHITE:
            case GC_YELLOW:
                {
                    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.
     */
    public void reset() {
        this.markedObjects = 0;
    }

    /**
     * Process all objects on the markstack, until the markstack is empty.
     */
    protected void mark() {
        while (!stack.isEmpty()) {
            final Object object = stack.pop();
            markedObjects++;
            final VmType vmClass = helper.getVmClass(object);
            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 (!((VmArrayClass) vmClass).isPrimitiveArray()) {
                    markArray(object);
                }
            } else {
                markObject(object, (VmNormalClass) vmClass);
                if (object instanceof VmThread) {
                    try {
                        markThreadStack((VmThread) object);
                    } catch (ClassCastException ex) {
                        Unsafe.debug("VmThread");
                        Unsafe.debug(object.getClass().getName());
                        helper.die("GCMarkVisitor.mark");
                    }
                }
            }
            processChild(helper.getTib(object));
            final Monitor monitor = helper.getInflatedMonitor(object, arch);
            if (monitor != null) {
                processChild(monitor);
            }
            final int gcColor = helper.getObjectColor(object);
            helper.atomicChangeObjectColor(object, gcColor, GC_BLACK);
        }
    }

    /**
     * Mark all elements in the given array. The array must contain references
     * only.
     * 
     * @param object
     */
    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) {
                    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
     */
    private void markObject(Object object, VmNormalClass vmClass) {
        final int[] referenceOffsets = vmClass.getReferenceOffsets();
        final int cnt = referenceOffsets.length;
        final int size = vmClass.getObjectSize();
        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 = helper.getObject(object, offset);
                if (child != null) {
                    processChild(child);
                }
            }
        }
    }

    /**
     * Mark all objects on the stack of the given thread
     * 
     * @param thread
     */
    private void markThreadStack(VmThread thread) {
        // For now do it stupid, but safe, just scan the whole stack.
        final int stackSize = thread.getStackSize();
        final Object stack = helper.getStack(thread);
        if (stack != null) {
            for (int i = 0; i < stackSize; i += slotSize) {
                Address child = Unsafe.getAddress(stack, i);
                if (child != null) {
                    if (heapManager.isObject(child)) {
                        processChild(child);
                    }
                }
            }
        }
    }

    /**
     * Process a child of an object (this child is a reference).
     * 
     * @param child
     */
    private void processChild(Object child) {
        final int gcColor = helper.getObjectColor(child);
        if (gcColor <= GC_WHITE) {
            // Yellow or White
            helper.atomicChangeObjectColor(child, gcColor, GC_GREY);
            stack.push(child);
        }
    }

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

    /**
     * Gets the rootSet attribute.
     * 
     * @return boolean
     */
    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.
     */
    public void setRootSet(boolean b) {
        rootSet = b;
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?