OSDN Git Service

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