Alloc.cpp revision ea4c6e57a48e08eacbf08520c64133175e7d5da0
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
71bool dvmGcStartupClasses()
72{
73    ClassObject *klass = dvmFindSystemClass("Ljava/lang/Daemons;");
74    if (klass == NULL) {
75        return false;
76    }
77    Method *method = dvmFindDirectMethodByDescriptor(klass, "start", "()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
88/*
89 * Create a "stock instance" of an exception class.
90 */
91static Object* createStockException(const char* descriptor, const char* msg)
92{
93    Thread* self = dvmThreadSelf();
94    StringObject* msgStr = NULL;
95    ClassObject* clazz;
96    Method* init;
97    Object* obj;
98
99    /* find class, initialize if necessary */
100    clazz = dvmFindSystemClass(descriptor);
101    if (clazz == NULL) {
102        LOGE("Unable to find %s", descriptor);
103        return NULL;
104    }
105
106    init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
107            "(Ljava/lang/String;)V");
108    if (init == NULL) {
109        LOGE("Unable to find String-arg constructor for %s", descriptor);
110        return NULL;
111    }
112
113    obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
114    if (obj == NULL)
115        return NULL;
116
117    if (msg == NULL) {
118        msgStr = NULL;
119    } else {
120        msgStr = dvmCreateStringFromCstr(msg);
121        if (msgStr == NULL) {
122            LOGW("Could not allocate message string \"%s\"", msg);
123            dvmReleaseTrackedAlloc(obj, self);
124            return NULL;
125        }
126    }
127
128    JValue unused;
129    dvmCallMethod(self, init, obj, &unused, msgStr);
130    if (dvmCheckException(self)) {
131        dvmReleaseTrackedAlloc((Object*) msgStr, self);
132        dvmReleaseTrackedAlloc(obj, self);
133        return NULL;
134    }
135
136    dvmReleaseTrackedAlloc((Object*) msgStr, self);     // okay if msgStr NULL
137    return obj;
138}
139
140/*
141 * Create some "stock" exceptions.  These can be thrown when the system is
142 * too screwed up to allocate and initialize anything, or when we don't
143 * need a meaningful stack trace.
144 *
145 * We can't do this during the initial startup because we need to execute
146 * the constructors.
147 */
148bool dvmCreateStockExceptions()
149{
150    /*
151     * Pre-allocate some throwables.  These need to be explicitly added
152     * to the GC's root set (see dvmHeapMarkRootSet()).
153     */
154    gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;",
155        "[memory exhausted]");
156    dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
157    gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;",
158        "[pre-allocated]");
159    dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
160    gDvm.noClassDefFoundErrorObj =
161        createStockException("Ljava/lang/NoClassDefFoundError;",
162            "[generic]");
163    dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL);
164
165    if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL ||
166        gDvm.noClassDefFoundErrorObj == NULL)
167    {
168        LOGW("Unable to create stock exceptions");
169        return false;
170    }
171
172    return true;
173}
174
175
176/*
177 * Create an instance of the specified class.
178 *
179 * Returns NULL and throws an exception on failure.
180 */
181Object* dvmAllocObject(ClassObject* clazz, int flags)
182{
183    Object* newObj;
184
185    assert(clazz != NULL);
186    assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
187
188    /* allocate on GC heap; memory is zeroed out */
189    newObj = (Object*)dvmMalloc(clazz->objectSize, flags);
190    if (newObj != NULL) {
191        DVM_OBJECT_INIT(newObj, clazz);
192        dvmTrackAllocation(clazz, clazz->objectSize);   /* notify DDMS */
193    }
194
195    return newObj;
196}
197
198/*
199 * Create a copy of an object, for Object.clone().
200 *
201 * We use the size actually allocated, rather than obj->clazz->objectSize,
202 * because the latter doesn't work for array objects.
203 */
204Object* dvmCloneObject(Object* obj, int flags)
205{
206    assert(dvmIsValidObject(obj));
207    ClassObject* clazz = obj->clazz;
208
209    /* Class.java shouldn't let us get here (java.lang.Class is final
210     * and does not implement Clonable), but make extra sure.
211     * A memcpy() clone will wreak havoc on a ClassObject's "innards".
212     */
213    assert(!dvmIsTheClassClass(clazz));
214
215    size_t size;
216    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
217        size = dvmArrayObjectSize((ArrayObject *)obj);
218    } else {
219        size = clazz->objectSize;
220    }
221
222    Object* copy = (Object*)dvmMalloc(size, flags);
223    if (copy == NULL)
224        return NULL;
225
226    DVM_OBJECT_INIT(copy, clazz);
227    size_t offset = sizeof(Object);
228    /* Copy instance data.  We assume memcpy copies by words. */
229    memcpy((char*)copy + offset, (char*)obj + offset, size - offset);
230
231    /* Mark the clone as finalizable if appropriate. */
232    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
233        dvmSetFinalizable(copy);
234    }
235
236    dvmTrackAllocation(clazz, size);    /* notify DDMS */
237
238    return copy;
239}
240
241
242/*
243 * Track an object that was allocated internally and isn't yet part of the
244 * VM root set.
245 *
246 * We could do this per-thread or globally.  If it's global we don't have
247 * to do the thread lookup but we do have to synchronize access to the list.
248 *
249 * "obj" must not be NULL.
250 *
251 * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will
252 * usually be NULL since we're being called from dvmMalloc().
253 */
254void dvmAddTrackedAlloc(Object* obj, Thread* self)
255{
256    if (self == NULL)
257        self = dvmThreadSelf();
258
259    assert(obj != NULL);
260    assert(self != NULL);
261    if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
262        LOGE("threadid=%d: unable to add %p to internal ref table",
263            self->threadId, obj);
264        dvmDumpThread(self, false);
265        dvmAbort();
266    }
267}
268
269/*
270 * Stop tracking an object.
271 *
272 * We allow attempts to delete NULL "obj" so that callers don't have to wrap
273 * calls with "if != NULL".
274 */
275void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
276{
277    if (obj == NULL)
278        return;
279
280    if (self == NULL)
281        self = dvmThreadSelf();
282    assert(self != NULL);
283
284    if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
285            self->internalLocalRefTable.table, obj))
286    {
287        LOGE("threadid=%d: failed to remove %p from internal ref table",
288            self->threadId, obj);
289        dvmAbort();
290    }
291}
292
293
294/*
295 * Explicitly initiate garbage collection.
296 */
297void dvmCollectGarbage()
298{
299    if (gDvm.disableExplicitGc) {
300        return;
301    }
302    dvmLockHeap();
303    dvmWaitForConcurrentGcToComplete();
304    dvmCollectGarbageInternal(GC_EXPLICIT);
305    dvmHeapSourceTrimHeaps();
306    dvmUnlockHeap();
307}
308
309struct CountContext {
310    const ClassObject *clazz;
311    size_t count;
312};
313
314static void countInstancesOfClassCallback(Object *obj, void *arg)
315{
316    CountContext *ctx = (CountContext *)arg;
317    assert(ctx != NULL);
318    if (obj->clazz == ctx->clazz) {
319        ctx->count += 1;
320    }
321}
322
323size_t dvmCountInstancesOfClass(const ClassObject *clazz)
324{
325    CountContext ctx = { clazz, 0 };
326    dvmLockHeap();
327    HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
328    dvmHeapBitmapWalk(bitmap, countInstancesOfClassCallback, &ctx);
329    dvmUnlockHeap();
330    return ctx.count;
331}
332
333static void countAssignableInstancesOfClassCallback(Object *obj, void *arg)
334{
335    CountContext *ctx = (CountContext *)arg;
336    assert(ctx != NULL);
337    if (obj->clazz != NULL && dvmInstanceof(obj->clazz, ctx->clazz)) {
338        ctx->count += 1;
339    }
340}
341
342size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz)
343{
344    CountContext ctx = { clazz, 0 };
345    dvmLockHeap();
346    HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
347    dvmHeapBitmapWalk(bitmap, countAssignableInstancesOfClassCallback, &ctx);
348    dvmUnlockHeap();
349    return ctx.count;
350}
351
352bool dvmIsHeapAddress(void *address)
353{
354    return address != NULL && (((uintptr_t) address & (8-1)) == 0);
355}
356
357bool dvmIsNonMovingObject(const Object* object)
358{
359    return true;
360}
361