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.MagicPermission;
24
import org.jnode.vm.VmMagic;
25
import org.jnode.vm.classmgr.ObjectFlags;
26
import org.jnode.vm.memmgr.HeapHelper;
27
import org.jnode.vm.memmgr.VmWriteBarrier;
28
import org.vmmagic.pragma.UninterruptiblePragma;
29
import org.vmmagic.unboxed.Address;
30
import org.vmmagic.unboxed.ObjectReference;
31
import org.vmmagic.unboxed.Offset;
32
33
/**
34
 * @author ismael
35
 */
36
@MagicPermission
37
final class GenWriteBarrier extends VmWriteBarrier {
38
39
    /**
40
     * The heap helper
41
     */
42
    private final HeapHelper helper;
43
44
    /**
45
     * Is the write barrier active?
46
     */
47
    private boolean active;
48
49
    /**
50
     * Are there any object colors changed by the write barrier, since the last
51
     * reset
52
     */
53
    private boolean changed;
54
55
    private int arrayCopyCount;
56
57
    private int arrayStoreCount;
58
59
    private int putFieldCount;
60
61
    private int putStaticCount;
62
    
63
    private final Offset nbRefOffset;
64
    
65
    /**
66
     * Initialize this instance.
67
     */
68
    public GenWriteBarrier(HeapHelper helper, Offset nbRefOffset) {
69
        this.helper = helper;
70
        this.nbRefOffset = nbRefOffset;
71
    }
72
73
    /**
74
     * @see org.jnode.vm.memmgr.VmWriteBarrier#arrayCopyWriteBarrier(java.lang.Object[],
75
     *      int, int)
76
     */
77
    public final void arrayCopyWriteBarrier(Object array, int start, int end)
78
        throws UninterruptiblePragma {
79
        if (active) {
80
            for(int i = start; i <= end; i++) {
81
                incRefs(getObjAddrAtOffset(array, i));
82
            }
83
        }
84
        // The source array is already reachable, so by definition, all
85
        // entries will be reachable.
86
        // So we do nothing here
87
        arrayCopyCount++;
88
    }
89
90
    /**
91
     * @see org.jnode.vm.memmgr.VmWriteBarrier#arrayStoreWriteBarrier(java.lang.Object,
92
     *      int, java.lang.Object)
93
     */
94
    public final void arrayStoreWriteBarrier(Object ref, int index, Object value)
95
        throws UninterruptiblePragma {
96
        if (active) {
97
            shade(value);
98
            decRefs(getObjAddrAtOffset(ref, index));
99
            incRefs(ObjectReference.fromObject(value).toAddress());
100
        }
101
        arrayStoreCount++;
102
    }
103
104
    /**
105
     * @see org.jnode.vm.memmgr.VmWriteBarrier#putfieldWriteBarrier(java.lang.Object,
106
     *      int, java.lang.Object)
107
     */
108
    public final void putfieldWriteBarrier(Object ref, int offset, Object value)
109
        throws UninterruptiblePragma {
110
        if (active) {
111
            shade(value);
112
            decRefs(getObjAddrAtOffset(ref, offset));
113
            incRefs(ObjectReference.fromObject(value).toAddress());
114
        }
115
        putFieldCount++;
116
    }
117
118
    /**
119
     * @see org.jnode.vm.memmgr.VmWriteBarrier#putstaticWriteBarrier(boolean, int,
120
     *      java.lang.Object)
121
     */
122
    public final void putstaticWriteBarrier(boolean shared, int staticsIndex, Object value)
123
        throws UninterruptiblePragma {
124
        if (active) {
125
            shade(value);
126
            //staticObjects.push(value);
127
        }
128
        putStaticCount++;
129
    }
130
131
    /**
132
     * Set the GC color of the given value to gray if it is white.
133
     *
134
     * @param value
135
     */
136
    private final void shade(Object value) throws UninterruptiblePragma {
137
        if (value != null) {
138
            while (true) {
139
                final int gcColor = VmMagic.getObjectColor(value);
140
                if (gcColor > ObjectFlags.GC_WHITE) {
141
                    // Not white or yellow, we're done
142
                    return;
143
                }
144
                if (helper.atomicChangeObjectColor(value, gcColor,
145
                    ObjectFlags.GC_GREY)) {
146
                    // Change to grey, we're done
147
                    changed = true;
148
                    return;
149
                }
150
            }
151
        }
152
    }
153
154
    private final Address getObjAddrAtOffset(Object ref, int offset) {
155
        final Address refAddr = ObjectReference.fromObject(ref).toAddress();
156
        return refAddr.add(Offset.fromIntZeroExtend(offset)).loadAddress();
157
    }
158
159
    private final void decRefs(Address objAddr) {
160
        if(objAddr.isZero()) return;
161
        int nbRefs = objAddr.loadInt(nbRefOffset);
162
        objAddr.store(--nbRefs, nbRefOffset);
163
    }
164
    
165
    private final void incRefs(Address objAddr) {
166
        if(objAddr.isZero()) return;
167
        int nbRefs = objAddr.loadInt(nbRefOffset);
168
        objAddr.store(++nbRefs, nbRefOffset);
169
    }
170
171
    public String toString() {
172
        return "arrayCopy: " + arrayCopyCount + ", arrayStore: "
173
            + arrayStoreCount + ", putField: " + putFieldCount
174
            + ", putStatic: " + putStaticCount;
175
    }
176
177
    /**
178
     * @param active The active to set.
179
     */
180
    final void setActive(boolean active) {
181
        this.changed = false;
182
        this.active = active;
183
    }
184
185
    /**
186
     * @return Returns the changed.
187
     */
188
    final boolean isChanged() {
189
        return this.changed;
190
    }
191
192
    /**
193
     * Reset the changed attribute to false.
194
     */
195
    final void resetChanged() {
196
        this.changed = false;
197
    }
198
}