1
/*
2
 * $Id$
3
 *
4
 * Copyright (C) 2003-2009 JNode.org
5
 *
6
 * This library is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation; either version 2.1 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful, but 
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
14
 * License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17
 * along with this library; If not, write to the Free Software Foundation, Inc., 
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
 */
20
 
21
package org.jnode.vm.memmgr.generational;
22
23
import org.jnode.annotation.Inline;
24
import org.jnode.annotation.MagicPermission;
25
import org.jnode.vm.ObjectVisitor;
26
import org.jnode.vm.Unsafe;
27
import org.jnode.vm.VmArchitecture;
28
import org.jnode.vm.VmMagic;
29
import org.jnode.vm.classmgr.ObjectFlags;
30
import org.jnode.vm.classmgr.VmNormalClass;
31
import org.jnode.vm.classmgr.VmType;
32
import org.jnode.vm.memmgr.HeapHelper;
33
import org.jnode.vm.scheduler.Monitor;
34
import org.vmmagic.unboxed.Address;
35
import org.vmmagic.unboxed.ObjectReference;
36
import org.vmmagic.unboxed.Offset;
37
38
39
/**
40
 * @author Ewout Prangsma (epr@users.sourceforge.net)
41
 */
42
@MagicPermission
43
final class GenGCVerifyVisitor extends ObjectVisitor {
44
45
    private HeapHelper helper;
46
    private GenHeapManager heapManager;
47
    private VmArchitecture arch;
48
    private int errorCount;
49
50
    public GenGCVerifyVisitor(GenHeapManager heapManager, VmArchitecture arch) {
51
        this.helper = heapManager.getHelper();
52
        this.heapManager = heapManager;
53
        this.arch = arch;
54
    }
55
56
    public final void reset() {
57
        errorCount = 0;
58
    }
59
60
    /**
61
     * @see org.jnode.vm.ObjectVisitor#visit(java.lang.Object)
62
     */
63
    @Override
64
    public final boolean visit(Object object) {
65
        final int color = VmMagic.getObjectColor(object);
66
        if (color == ObjectFlags.GC_YELLOW) {
67
            // Ignore objects that need to be finalized.
68
            return true;
69
        }
70
71
        if (VmMagic.isFinalized(object)) {
72
            // Ignore finalized objects that need to be freed
73
            return true;
74
        }
75
76
        VmType<?> vmClass;
77
        try {        
78
            vmClass = VmMagic.getObjectType(object);
79
        } catch (NullPointerException ex) {
80
            if (object == null) {
81
                helper.die("GCVerifyError: null object");
82
            } else if (VmMagic.getTIB(object) == null) {
83
                helper.die("GCVerifyError: null TIB");
84
            } else {
85
                helper.die("GCVerifyError: other NPE");
86
            }
87
            /* not reached */
88
            throw ex;
89
        }
90
        if (vmClass == null) {
91
            helper.die("GCVerifyError: vmClass");
92
        } else if (vmClass.isArray()) {
93
            if (!vmClass.isPrimitiveArray()) {
94
                verifyArray(object);
95
            }
96
        } else {
97
            verifyObject(object, (VmNormalClass<?>) vmClass);
98
        }
99
        verifyChild(VmMagic.getTIB(object), object, "tib");
100
        final Monitor monitor = helper.getInflatedMonitor(object, arch);
101
        if (monitor != null) {
102
            verifyChild(monitor, object, "monitor");
103
        }
104
        return (errorCount == 0);
105
    }
106
107
    @Inline
108
    private final void verifyArray(Object object) {
109
        final Object[] arr = (Object[]) object;
110
        final int length = arr.length;
111
        for (int i = 0; i < length; i++) {
112
            final Object child = arr[i];
113
            if (child != null) {
114
                verifyChild(child, object, "Object[]");
115
            }
116
        }
117
118
    }
119
120
    @Inline
121
    private final void verifyObject(Object object, VmNormalClass<?> vmClass) {
122
        final int[] referenceOffsets = vmClass.getReferenceOffsets();
123
        final int cnt = referenceOffsets.length;
124
        final int size = vmClass.getObjectSize();
125
        final Address ptr = ObjectReference.fromObject(object).toAddress();
126
        for (int i = 0; i < cnt; i++) {
127
            int offset = referenceOffsets[i];
128
            if ((offset < 0) || (offset >= size)) {
129
                Unsafe.debug("reference offset out of range!");
130
                Unsafe.debug(vmClass.getName());
131
                helper.die("Class internal error");
132
            } else {
133
                final Object child = ptr.loadObjectReference(Offset.fromIntZeroExtend(offset)).toObject();
134
                if (child != null) {
135
                    verifyChild(child, object, "object child");
136
                }
137
            }
138
        }
139
    }
140
141
    @Inline
142
    private final void verifyChild(Object child, Object parent, String where) {
143
        if (child != null) {
144
            final ObjectReference childRef = ObjectReference.fromObject(child);
145
            if (!heapManager.isObject(childRef.toAddress())) {
146
                Unsafe.debug("GCVerifyError: in ");
147
                Unsafe.debug(where);
148
                Unsafe.debug(", parent type ");
149
                Unsafe.debug(VmMagic.getObjectType(parent).getName());
150
                Unsafe.debug(VmMagic.getObjectColor(parent));
151
                Unsafe.debug("; child (");
152
                Unsafe.debug(childRef.toAddress().toInt());
153
                Unsafe.debug(") is not an object ");
154
                Unsafe.debug(VmMagic.getObjectColor(childRef));
155
                errorCount++;
156
            }
157
        }
158
    }
159
160
    /**
161
     * @return Returns the errorCount.
162
     */
163
    public final int getErrorCount() {
164
        return this.errorCount;
165
    }
166
}