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;
22
23
import org.jnode.annotation.MagicPermission;
24
import org.jnode.annotation.Uninterruptible;
25
import org.jnode.vm.classmgr.ObjectFlags;
26
import org.jnode.vm.classmgr.ObjectLayout;
27
import org.jnode.vm.classmgr.VmMethod;
28
import org.jnode.vm.isolate.VmIsolate;
29
import org.jnode.vm.memmgr.HeapHelper;
30
import org.jnode.vm.memmgr.VmHeapManager;
31
import org.jnode.vm.scheduler.Monitor;
32
import org.jnode.vm.scheduler.MonitorManager;
33
import org.jnode.vm.scheduler.VmProcessor;
34
import org.jnode.vm.scheduler.VmThread;
35
import org.jnode.vm.scheduler.VmThreadVisitor;
36
import org.vmmagic.unboxed.Address;
37
import org.vmmagic.unboxed.Extent;
38
import org.vmmagic.unboxed.ObjectReference;
39
import org.vmmagic.unboxed.Offset;
40
import org.vmmagic.unboxed.Word;
41
42
/**
43
 * @author Ewout Prangsma (epr@users.sourceforge.net)
44
 */
45
@MagicPermission
46
@Uninterruptible
47
final class HeapHelperImpl extends HeapHelper {
48
49
    private static final class ThreadRootVisitor extends VmThreadVisitor {
50
51
        private VmHeapManager heapManager;
52
53
        private ObjectVisitor visitor;
54
55
        public final void initialize(ObjectVisitor visitor,
56
                                     VmHeapManager heapManager) {
57
            this.visitor = visitor;
58
            this.heapManager = heapManager;
59
        }
60
61
        public boolean visit(VmThread thread) {
62
            return thread.visit(visitor, heapManager);
63
        }
64
    }
65
66
    private final int flagsOffset;
67
    private final int ageOffset;
68
    private final int nbRefsOffset;
69
70
    private final ThreadRootVisitor threadRootVisitor;
71
72
    /**
73
     * Initialize this instance.
74
     *
75
     * @param arch
76
     */
77
    public HeapHelperImpl(VmArchitecture arch) {
78
        if (Vm.getVm() != null) {
79
            throw new SecurityException(
80
                "Cannot instantiate HeapHelpImpl at runtime");
81
        }
82
        final int refSize = arch.getReferenceSize();
83
        flagsOffset = ObjectLayout.FLAGS_SLOT * refSize;
84
        ageOffset = ObjectLayout.COLLECTION_AGE_SLOT * refSize;
85
        nbRefsOffset = ObjectLayout.NB_REFS_SLOT * refSize;
86
        this.threadRootVisitor = new ThreadRootVisitor();
87
    }
88
89
    /**
90
     * @see org.jnode.vm.memmgr.HeapHelper#allocateBlock(Extent)
91
     */
92
    public final Address allocateBlock(Extent size) {
93
        return MemoryBlockManager.allocateBlock(size);
94
    }
95
96
    /**
97
     * Change the color of the given object from oldColor to newColor.
98
     *
99
     * @param dst
100
     * @param oldColor
101
     * @param newColor
102
     * @return True if the color was changed, false if the current color of the
103
     *         object was not equal to oldColor.
104
     */
105
    public boolean atomicChangeObjectColor(Object dst, int oldColor,
106
                                           int newColor) {
107
        final Address addr = ObjectReference.fromObject(dst).toAddress().add(
108
            flagsOffset);
109
        for (;;) {
110
            Word oldValue = addr.prepareWord();
111
            if (oldValue
112
                .and(Word.fromIntZeroExtend(ObjectFlags.GC_COLOUR_MASK))
113
                .NE(Word.fromIntZeroExtend(oldColor))) {
114
                return false;
115
            }
116
            Word newValue = oldValue.and(
117
                Word.fromIntZeroExtend(ObjectFlags.GC_COLOUR_MASK).not())
118
                .or(Word.fromIntZeroExtend(newColor));
119
            if (addr.attempt(oldValue, newValue)) {
120
                return true;
121
            }
122
        }
123
    }
124
    
125
    public int incrementAge(Object obj)
126
    {
127
        final Address addr = ObjectReference.fromObject(obj).toAddress().add(
128
                ageOffset);
129
        for (;;) {
130
            int oldValue = addr.prepareInt();
131
            if (oldValue == ObjectFlags.OLD_OBJECT) {
132
                return ObjectFlags.OLD_OBJECT;
133
            }
134
            int newValue = oldValue + 1;
135
            if (addr.attempt(oldValue, newValue)) {
136
                return newValue;
137
            }
138
        }
139
    }
140
    
141
    public boolean setOld(Object obj)
142
    {
143
        final Address addr = ObjectReference.fromObject(obj).toAddress().add(
144
                ageOffset);
145
        for (;;) {
146
            int oldValue = addr.prepareInt();
147
            if (oldValue == ObjectFlags.OLD_OBJECT) {
148
                return false;
149
            }
150
            int newValue = ObjectFlags.OLD_OBJECT;
151
            if (addr.attempt(oldValue, newValue)) {
152
                return true;
153
            }
154
        }
155
    }
156
    
157
    public int getNbRefs(Object obj)
158
    {
159
        final Address addr = ObjectReference.fromObject(obj).toAddress();
160
        
161
        if(addr.loadInt(Offset.fromIntZeroExtend(ageOffset)) == ObjectFlags.OLD_OBJECT) return -1;
162
        
163
        return addr.loadInt(Offset.fromIntZeroExtend(nbRefsOffset));
164
    }
165
    
166
    public int decRef(Object obj)
167
    {
168
        final Address addr = ObjectReference.fromObject(obj).toAddress().add(
169
                nbRefsOffset);
170
        for (;;) {
171
            int oldValue = addr.prepareInt();
172
            if (oldValue <= 0) {
173
                return oldValue;
174
            }
175
            int newValue = oldValue - 1;
176
            if (addr.attempt(oldValue, newValue)) {
177
                return newValue;
178
            }
179
        }
180
    }
181
182
    /**
183
     * @see org.jnode.vm.memmgr.HeapHelper#clear(Address, Extent)
184
     */
185
    public final void clear(Address dst, Extent size) {
186
        Unsafe.clear(dst, size);
187
    }
188
189
    /**
190
     * @see org.jnode.vm.memmgr.HeapHelper#clear(Address, int)
191
     */
192
    public final void clear(Address dst, int size) {
193
        Unsafe.clear(dst, Extent.fromIntSignExtend(size));
194
    }
195
196
    /**
197
     * @see org.jnode.vm.memmgr.HeapHelper#copy(Address, Address, int)
198
     */
199
    public final void copy(Address src, Address dst, Extent size) {
200
        Unsafe.copy(src, dst, size);
201
    }
202
203
    /**
204
     * @see org.jnode.vm.memmgr.HeapHelper#die(java.lang.String)
205
     */
206
    public final void die(String msg) {
207
        try {
208
            VmProcessor.current().getArchitecture().getStackReader()
209
                .debugStackTrace();
210
        } finally {
211
            Unsafe.die(msg);
212
        }
213
    }
214
215
    /**
216
     * @see org.jnode.vm.memmgr.HeapHelper#getBootHeapEnd()
217
     */
218
    public final Address getBootHeapEnd() {
219
        return Unsafe.getBootHeapEnd();
220
    }
221
222
    /**
223
     * @see org.jnode.vm.memmgr.HeapHelper#getBootHeapStart()
224
     */
225
    public final Address getBootHeapStart() {
226
        return Unsafe.getBootHeapStart();
227
    }
228
229
    /**
230
     * @see org.jnode.vm.memmgr.HeapHelper#getBootImageEnd()
231
     */
232
    public final Address getBootImageEnd() {
233
        return Unsafe.getBootHeapEnd();
234
    }
235
236
    /**
237
     * @see org.jnode.vm.memmgr.HeapHelper#getBootImageStart()
238
     */
239
    public final Address getBootImageStart() {
240
        return Unsafe.getKernelStart();
241
    }
242
243
    /**
244
     * @see org.jnode.vm.memmgr.HeapHelper#getHeapSize()
245
     */
246
    public Extent getHeapSize() {
247
        final Word end = Unsafe.getMemoryEnd().toWord();
248
        final Word start = Unsafe.getMemoryStart().toWord();
249
        return end.sub(start).toExtent();
250
    }
251
252
    /**
253
     * @see org.jnode.vm.memmgr.HeapHelper#getInflatedMonitor(java.lang.Object,
254
     *      org.jnode.vm.VmArchitecture)
255
     */
256
    public final Monitor getInflatedMonitor(Object object, VmArchitecture arch) {
257
        return MonitorManager.getInflatedMonitor(object);
258
    }
259
260
    /**
261
     * @see org.jnode.vm.memmgr.HeapHelper#invokeFinalizer(org.jnode.vm.classmgr.VmMethod,
262
     *      java.lang.Object)
263
     */
264
    public final void invokeFinalizer(VmMethod finalizer, Object object) {
265
        Unsafe.pushObject(object);
266
        Unsafe.invokeVoid(finalizer);
267
    }
268
269
    /**
270
     * Unblock all threads (on all processors). This method is called after a
271
     * call a call to {@link #stopThreadsAtSafePoint()}.
272
     */
273
    public void restartThreads() {
274
        VmMagic.currentProcessor().enableReschedule(true);
275
    }
276
277
    /**
278
     * Mark the given object as finalized.
279
     *
280
     * @param dst
281
     */
282
    public final void setFinalized(Object dst) {
283
        final Address addr = ObjectReference.fromObject(dst).toAddress().add(
284
            flagsOffset);
285
        int oldValue;
286
        int newValue;
287
        do {
288
            oldValue = addr.prepareInt();
289
            if ((oldValue & ObjectFlags.STATUS_FINALIZED) != 0) {
290
                return;
291
            }
292
            newValue = oldValue | ObjectFlags.STATUS_FINALIZED;
293
        } while (!addr.attempt(oldValue, newValue));
294
        // } while (!Unsafe.atomicCompareAndSwap(addr, oldValue, newValue));
295
    }
296
297
    /**
298
     * Stop and block all threads (on all processors) on a GC safe point. Only
299
     * the calling thread (the GC thread) will continue.
300
     */
301
    public final void stopThreadsAtSafePoint() {
302
        VmMagic.currentProcessor().disableReschedule(true);
303
    }
304
305
    /**
306
     * Visit all roots of the object tree.
307
     *
308
     * @param visitor
309
     */
310
    public void visitAllRoots(ObjectVisitor visitor, VmHeapManager heapManager) {
311
        final Vm vm = Vm.getVm();
312
        if (!vm.getSharedStatics().walk(visitor)) {
313
            return;
314
        }
315
        if (!VmProcessor.current().getIsolatedStatics().walk(visitor)) {
316
            return;
317
        }
318
        if (!VmIsolate.walkIsolates(visitor)) {
319
            return;
320
        }
321
        threadRootVisitor.initialize(visitor, heapManager);
322
        VmMagic.currentProcessor().getScheduler().visitAllThreads(threadRootVisitor);
323
    }
324
325
    /**
326
     * @see org.jnode.vm.memmgr.HeapHelper#bootArchitecture(boolean)
327
     */
328
    public final void bootArchitecture(boolean emptyMMap) {
329
        Vm.getArch().boot(emptyMMap);
330
    }
331
}