Alloc.cpp revision 60fc806b679a3655c228b4093058c59941a49cfe
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16/*
17 * Garbage-collecting memory allocator.
18 */
19#include "Dalvik.h"
20#include "alloc/Heap.h"
21#include "alloc/HeapInternal.h"
22#include "alloc/HeapSource.h"
23
24/*
25 * Initialize the GC universe.
26 *
27 * We're currently using a memory-mapped arena to keep things off of the
28 * main heap.  This needs to be replaced with something real.
29 */
30bool dvmGcStartup()
31{
32    dvmInitMutex(&gDvm.gcHeapLock);
33    pthread_cond_init(&gDvm.gcHeapCond, NULL);
34    return dvmHeapStartup();
35}
36
37/*
38 * Post-zygote heap initialization, including starting
39 * the HeapWorker thread.
40 */
41bool dvmGcStartupAfterZygote()
42{
43    return dvmHeapStartupAfterZygote();
44}
45
46/*
47 * Shutdown the threads internal to the garbage collector.
48 */
49void dvmGcThreadShutdown()
50{
51    dvmHeapThreadShutdown();
52}
53
54/*
55 * Shut the GC down.
56 */
57void dvmGcShutdown()
58{
59    //TODO: grab and destroy the lock
60    dvmHeapShutdown();
61}
62
63/*
64 * Do any last-minute preparation before we call fork() for the first time.
65 */
66bool dvmGcPreZygoteFork()
67{
68    return dvmHeapSourceStartupBeforeFork();
69}
70
71static bool startGcClass(const char* klassName, const char* methodName)
72{
73    ClassObject *klass = dvmFindSystemClass(klassName);
74    if (klass == NULL) {
75        return false;
76    }
77    Method *method = dvmFindDirectMethodByDescriptor(klass, methodName, "()V");
78    if (method == NULL) {
79        return false;
80    }
81    Thread *self = dvmThreadSelf();
82    assert(self != NULL);
83    JValue unusedResult;
84    dvmCallMethod(self, method, NULL, &unusedResult);
85    return true;
86}
87
88bool dvmGcStartupClasses()
89{
90    bool success =
91            startGcClass("Ljava/lang/ref/ReferenceQueueThread;",
92                         "startReferenceQueue") &&
93            startGcClass("Ljava/lang/FinalizerThread;",
94                         "startFinalizer");
95    return success;
96}
97
98/*
99 * Create a "stock instance" of an exception class.
100 */
101static Object* createStockException(const char* descriptor, const char* msg)
102{
103    Thread* self = dvmThreadSelf();
104    StringObject* msgStr = NULL;
105    ClassObject* clazz;
106    Method* init;
107    Object* obj;
108
109    /* find class, initialize if necessary */
110    clazz = dvmFindSystemClass(descriptor);
111    if (clazz == NULL) {
112        LOGE("Unable to find %s", descriptor);
113        return NULL;
114    }
115
116    init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
117            "(Ljava/lang/String;)V");
118    if (init == NULL) {
119        LOGE("Unable to find String-arg constructor for %s", descriptor);
120        return NULL;
121    }
122
123    obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
124    if (obj == NULL)
125        return NULL;
126
127    if (msg == NULL) {
128        msgStr = NULL;
129    } else {
130        msgStr = dvmCreateStringFromCstr(msg);
131        if (msgStr == NULL) {
132            LOGW("Could not allocate message string \"%s\"", msg);
133            dvmReleaseTrackedAlloc(obj, self);
134            return NULL;
135        }
136    }
137
138    JValue unused;
139    dvmCallMethod(self, init, obj, &unused, msgStr);
140    if (dvmCheckException(self)) {
141        dvmReleaseTrackedAlloc((Object*) msgStr, self);
142        dvmReleaseTrackedAlloc(obj, self);
143        return NULL;
144    }
145
146    dvmReleaseTrackedAlloc((Object*) msgStr, self);     // okay if msgStr NULL
147    return obj;
148}
149
150/*
151 * Create some "stock" exceptions.  These can be thrown when the system is
152 * too screwed up to allocate and initialize anything, or when we don't
153 * need a meaningful stack trace.
154 *
155 * We can't do this during the initial startup because we need to execute
156 * the constructors.
157 */
158bool dvmCreateStockExceptions()
159{
160    /*
161     * Pre-allocate some throwables.  These need to be explicitly added
162     * to the GC's root set (see dvmHeapMarkRootSet()).
163     */
164    gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;",
165        "[memory exhausted]");
166    dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
167    gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;",
168        "[pre-allocated]");
169    dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
170    gDvm.noClassDefFoundErrorObj =
171        createStockException("Ljava/lang/NoClassDefFoundError;",
172            "[generic]");
173    dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL);
174
175    if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL ||
176        gDvm.noClassDefFoundErrorObj == NULL)
177    {
178        LOGW("Unable to create stock exceptions");
179        return false;
180    }
181
182    return true;
183}
184
185
186/*
187 * Create an instance of the specified class.
188 *
189 * Returns NULL and throws an exception on failure.
190 */
191Object* dvmAllocObject(ClassObject* clazz, int flags)
192{
193    Object* newObj;
194
195    assert(clazz != NULL);
196    assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
197
198    /* allocate on GC heap; memory is zeroed out */
199    newObj = (Object*)dvmMalloc(clazz->objectSize, flags);
200    if (newObj != NULL) {
201        DVM_OBJECT_INIT(newObj, clazz);
202        dvmTrackAllocation(clazz, clazz->objectSize);   /* notify DDMS */
203    }
204
205    return newObj;
206}
207
208/*
209 * Create a copy of an object, for Object.clone().
210 *
211 * We use the size actually allocated, rather than obj->clazz->objectSize,
212 * because the latter doesn't work for array objects.
213 */
214Object* dvmCloneObject(Object* obj, int flags)
215{
216    assert(dvmIsValidObject(obj));
217    ClassObject* clazz = obj->clazz;
218
219    /* Class.java shouldn't let us get here (java.lang.Class is final
220     * and does not implement Clonable), but make extra sure.
221     * A memcpy() clone will wreak havoc on a ClassObject's "innards".
222     */
223    assert(!dvmIsTheClassClass(clazz));
224
225    size_t size;
226    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
227        size = dvmArrayObjectSize((ArrayObject *)obj);
228    } else {
229        size = clazz->objectSize;
230    }
231
232    Object* copy = (Object*)dvmMalloc(size, flags);
233    if (copy == NULL)
234        return NULL;
235
236    DVM_OBJECT_INIT(copy, clazz);
237    size_t offset = sizeof(Object);
238    /* Copy instance data.  We assume memcpy copies by words. */
239    memcpy((char*)copy + offset, (char*)obj + offset, size - offset);
240
241    /* Mark the clone as finalizable if appropriate. */
242    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
243        dvmSetFinalizable(copy);
244    }
245
246    dvmTrackAllocation(clazz, size);    /* notify DDMS */
247
248    return copy;
249}
250
251
252/*
253 * Track an object that was allocated internally and isn't yet part of the
254 * VM root set.
255 *
256 * We could do this per-thread or globally.  If it's global we don't have
257 * to do the thread lookup but we do have to synchronize access to the list.
258 *
259 * "obj" must not be NULL.
260 *
261 * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will
262 * usually be NULL since we're being called from dvmMalloc().
263 */
264void dvmAddTrackedAlloc(Object* obj, Thread* self)
265{
266    if (self == NULL)
267        self = dvmThreadSelf();
268
269    assert(obj != NULL);
270    assert(self != NULL);
271    if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
272        LOGE("threadid=%d: unable to add %p to internal ref table",
273            self->threadId, obj);
274        dvmDumpThread(self, false);
275        dvmAbort();
276    }
277}
278
279/*
280 * Stop tracking an object.
281 *
282 * We allow attempts to delete NULL "obj" so that callers don't have to wrap
283 * calls with "if != NULL".
284 */
285void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
286{
287    if (obj == NULL)
288        return;
289
290    if (self == NULL)
291        self = dvmThreadSelf();
292    assert(self != NULL);
293
294    if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
295            self->internalLocalRefTable.table, obj))
296    {
297        LOGE("threadid=%d: failed to remove %p from internal ref table",
298            self->threadId, obj);
299        dvmAbort();
300    }
301}
302
303
304/*
305 * Explicitly initiate garbage collection.
306 */
307void dvmCollectGarbage()
308{
309    if (gDvm.disableExplicitGc) {
310        return;
311    }
312    dvmLockHeap();
313    dvmWaitForConcurrentGcToComplete();
314    dvmCollectGarbageInternal(GC_EXPLICIT);
315    dvmUnlockHeap();
316}
317
318struct CountContext {
319    const ClassObject *clazz;
320    size_t count;
321};
322
323static void countInstancesOfClassCallback(void *ptr, void *arg)
324{
325    CountContext *ctx = (CountContext *)arg;
326    const Object *obj = (const Object *)ptr;
327
328    assert(ctx != NULL);
329    if (obj->clazz == ctx->clazz) {
330        ctx->count += 1;
331    }
332}
333
334size_t dvmCountInstancesOfClass(const ClassObject *clazz)
335{
336    CountContext ctx = { clazz, 0 };
337    dvmLockHeap();
338    HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
339    dvmHeapBitmapWalk(bitmap, countInstancesOfClassCallback, &ctx);
340    dvmUnlockHeap();
341    return ctx.count;
342}
343
344static void countAssignableInstancesOfClassCallback(void *ptr, void *arg)
345{
346    CountContext *ctx = (CountContext *)arg;
347    const Object *obj = (const Object *)ptr;
348
349    assert(ctx != NULL);
350    if (obj->clazz != NULL && dvmInstanceof(obj->clazz, ctx->clazz)) {
351        ctx->count += 1;
352    }
353}
354
355size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz)
356{
357    CountContext ctx = { clazz, 0 };
358    dvmLockHeap();
359    HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
360    dvmHeapBitmapWalk(bitmap, countAssignableInstancesOfClassCallback, &ctx);
361    dvmUnlockHeap();
362    return ctx.count;
363}
364
365bool dvmIsHeapAddress(void *address)
366{
367    return dvmHeapSourceContainsAddress(address);
368}
369
370bool dvmIsNonMovingObject(const Object* object)
371{
372    return true;
373}
374